Bitryon Logger Docs
GitHub
API Reference

Logging

The primary annotation for specify logs.

Annotation @Logging

Annotation methods or classes

import io.bitryon.logger.annotation.Logging;

@Logging
public class UserServiceImpl { // impelements UserService {

	public User getById(Long userId){
		return user;
	}
	
	@Logging(sanitizerPatterns="*/MASK$3(recipient)", skipRandom=Integer.MAX_VALUE >>> 1)// mask the recipient JSON/*EmailService.sendByNoRepply*
	public String sendVerificationUrl(String recipient, String verificationUrl) {
		return htmlContent;
	}
}

Parameters

ParameterTypeDefaultDescription
parametersbooleantrue

Log parameters when call to the method, or the methods of the class
true to log, false to skip;

returnsbooleantrue

Log return values of the method
true to log, false to skip.
It's suggested that print the returns to connect with the inputs
In other language, there could be multiple returns, or an array.

returnsAndParametersbooleanfalse

Log return values and parameters both when the method returns.
When passing by reference, the value inside object could be changed, so we want to print the whole when the method returns.

resetbooleanfalse

Reset the log/trace id, so the next call could be in new traces.

stepString""

The step of the code to print logs. Leave empty to let logger create the step of line of code as a stack.

catchExceptionsClass<? extends Throwable>[]{ Exception.class };

Log exception of the method.

skipThrowbooleanfalse

to throw exception when caught and logged. true will not throw the exception when caught and logged.

skipStacksint0

skip specified number of stacks when trace back the thread stack.
Must be greater than 0.

skipRandomintInteger.MAX_VALUE

the possibility to write logs for the method. will skip return and error as well.
random a Integer 0 <= random_int < Integer.MAX_VALUE, if skipRandom is smaller than random_int, skip it. Means the large skipRandom, the more chance to write logs. If keeps default Integer.MAX_VALUE, it will never skip by random_int; if it's negative, it will always skip.

sanitizerPatternsString[]{}

Patterns to sanitize sensitive info. If it starts with /, it must follow with a full pattern [/JSON/xxxx.method/X/MASK(key)], otherwise [X/MASK(key)]. multiple groups accepted [X/MASK(key1)/X/MASK(key2)].
More cases see the table below.

catchLoggingbooleanfalse

the catcher of the method annotated Logging. The catcher can be Logging.parameters/returns/parametersAndReturns false.

catchClassesClass<?>[]{}

the catcher classes.

catchPackagesString[]{}

the catcher packages. It must be exact match.

Sanitizer Pattern tokens

start with /, not end with /; can place multiple groups; $ is to pass parameters.
Or, start without / to match specified method by @Logging;

Sanitizer template: 
  /TYPE/Step/[placeholder: *]/FUNC(key1|key2)
  /TYPE/Step/[placeholder: *]/MD5(key1|key2)/[placeholder: KEY-base62]/AES(key1|key2)
  
Real case:
  /JSON/*Service*.java*.service.*UserService*#*/MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4/AES(driverLisenceId)/*/MASK$2(name)//SKIP(birthday),
  /JSON/*MedicService*#*/MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4/AES(driverLisenceId)/*/MASK$2(name)//SKIP(birthday),
  /JSON/*.java*.Medic*#*/*/MASK$4(deceases)/yyyy-MM-dd HH:mm:ss.ssss/DATE_FORMATER(timeCreated),
  /HTTP/*LoggingHttpRequestWebReader#readHttpRequest*/MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4/AES(driverLisenceId)/*/MASK$2(name)//SKIP(birthday) 
TokenDefaultDescription
%TYPEJSON / J
CONF("C"), -- configuration log. must be the first line of log for each file. repeatable.
METRIC("M"), -- reserved
TEXT("T"), -- print text only log
EXCEP("E"), -- print java exceptions into log
JSON("J"), -- print json log
HTTP("H"); -- print HTPP log
%Step""support wildcard match: /JSON/*Controller.java*controller.*Controller#*/*/MASK(encryptionKey)/*/MD5(sessionId|session_id)
%placeholder*for AES it's the key in base64.
%FUNCFUNC$1, 1 is to pass to the function, MD5$3. See details below.

Sanitizer Pattern functions

Functions won't change the value but only covert to the new.

EMPTY, -- set the string value of the keys to empty string
SKIP, -- skip the value of the key so the log doesn't print it.
POPULAR, -- capture it then scan the entire log to replace all. can use with others: POPULAR(MASK(key1))
AES, -- AES encryption.
MD5, -- MD5(key1) -> XWvr4b7h0XBFB79Irz1ny; MD5$1(key1) -> XWvr4b7h0XBFB79Irz1ny-423; 423 is the length of the original text
SHA1, -- similar with MD5
SHA256, -- similar with MD5
MASK, -- Mask the value of the key:
	 */MASK(key1) -> ***123456 -> *****; 
	 */MASK$3(key1) -> 12345678 ->123***678; 12345 -> 123***45
DATE_FORMATER: -- yyyy-hh-mm HH:MM:ss.ssss/DATE_FORMATER(key); the placeholder is the formatter. See java.text.SimpleDateFormat
FLOAT_FORMATER: -- #,##0.00/FLOAT_FORMATER(key); the placeholder is the formatter. See java.text.DecimalFormat
DECIMAL_FORMATER: -- same with FLOAT_FORMATER

LoggingUnit

It's a direct transformation of @Logging for the classes or interfaces can't annotate.

import io.bitryon.logger.annotation.LoggingUnit;
import io.bitryon.logger.spring.LoggingMethodPointcut;

public class UserServiceImpl { // impelements UserService {

	@Resource
	LoggingMethodPointcut loggingMethodPointcut;
	
	@Bean
	UserService getUserRPCService() {
		return (UserService) loggingMethodPointcut.proxyBeanInstance(// Pointcut to intercept the methods if log on interfaces or class without @Logging. 
				LoggingUnit.Builder().catchPackages("io.bitryon.example.web.service").build(),  //catchLoggingMethod(true)
					this.getProxyFactoryBean(UserService.class, this), UserService.class);
	}
}