Bitryon Logger Docs
GitHub
Get Started

Full Preview

This is all you need to run bitryon logger - although much info need to consume.

Configuration file

bitryon:
  logger:
    file-name: ./logs/${spring.application.name} # will be like  ./logs/bitryon-logging-java-spring-example.20250415-161023-565.0.log
    file-max-length: 536870912
    print-stdout: true # print to console
    print-file: true # write to file
    log-date-time-format: yyyy-MM-dd HH:mm:ss.SSS # UTC. the time on the head of the log. Leave blank will print System.currentTimeMillis
    log-async: true # false blocking IO; true NIO write files, it could lose part of logs if JVM crashes
    log-light: false # full step info, or light. true: MedicController.java#io.bitryon.web.controller.MedicController#query#123; no thread info, type JSON->J, false: #.MedicController#query#123 [the sanitizer-patterns may be slightly different].
    log-pretty: true # print pretty json and log, by new line and intends. close it in prd if needed.
    log-sanitizer-patterns: >
      /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) 

  app-node:
    http-header-id-type: 1 # write log/trace id to the http response header; 0 default no write header, 1 trace id, 2 step log id
    application-name: ${spring.application.name}
    host-id: node-123.test.test # unique, with file to identify unique file

  github: # optional
    host: https://github.com/
    source-paths: > 
      src/main/java
    repository: RepoOwner/${spring.application.name} # project on github
    branch: master
    commit: xxxxxxx

  boot-info: # for info purpose, bitryon don't use it
    version: 1.2.3 # the version of the app.
    internal-ip: 12.2.2.2
    external-ip: 12.2.2.2
    program: 1.2.2-1231321.jar
    region: use-1
    platform: 
      cloud: aws

Initiate bitryon logger

Initiate logger at the very beginning:

// In Spring 
public static void main(String[] args) {
	io.bitryon.logger.boostrap.LoggingProxyInitiation.premain(null); // must load before everything. 
	//or add https://github.com/FrankNPC/bitryon-logging-tracing-examples/blob/master/bitryon-logging-java-spring-example/src/main/resources/META-INF/spring.factories 
	new SpringApplicationBuilder(ServerBootApplication.class).run(args);
}
	
// In java
public static void main(String[] args) {
	LoggingProxyInitiation.premain(null);
	LoggerProvider provider = LoggerProvider.getProvider("bitryon_log.properties", null);
	new LoggingMethodIntercepter(provider);
}

Load bitryon logger

Load logger to write and read step log id (trace id) over HTTP:

// write step log id (trace id) header to the HTTP client, in your bean
public class ExampleWebHTTPClient {
	@Resource
	LoggerProvider bitryonLoggerProvider;
	
	public RestClient getRestClient() {
		return RestClient
			.builder(new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient())))
			.baseUrl(getBaseUrl())
			
			// write step log id to the http request header to the next app/service to form traces
			.requestInterceptor(new LoggingHttpClientHeaderWriterInterceptor(bitryonLoggerProvider))
			.build();
	}
}

// read step log id (trace id) header by filter in spring web 
@Configuration
@Import(value= {
	AutoConfigurationBitryonLogger.class, // to load the configs from application.yml for logging related beans
})
public class ExampleWebServerConfiguration {

	@Resource
	LoggerProvider bitryonLoggerProvider;

	// read step log id from last app/service/http request header to form traces, and log http payload for specific paths
	@Bean
	FilterRegistrationBean<LoggingHttpRequestWebFilter> loggingResetInFilter() {
		FilterRegistrationBean<LoggingHttpRequestWebFilter> reg = new FilterRegistrationBean<>(
				new LoggingHttpRequestWebFilter(bitryonLoggerProvider, true));
		reg.setOrder(Ordered.HIGHEST_PRECEDENCE);
		reg.addUrlPatterns("/api", "/api/*", "/remote_api/*");
		return reg;
	}
}

Write logs

Write logs through @Logging and logger.log() both:

package io.bitryon.example.web.service.rpc;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.springframework.stereotype.Service;

import io.bitryon.example.web.model.User;
import io.bitryon.logger.Logger;
import io.bitryon.logger.annotation.Logging;
import io.bitryon.spring.rmi.http.prodiver.Provider;
import jakarta.annotation.Resource;

@Provider("/remote_api/") // RPC service 
@Service
@Logging
public class UserServiceImpl { // impelements UserService {
	@Resource
	Logger logger;
	
	//private static final Logger logger = LoggerFactory.getLogger(); // both work. recommended

	public User getById(Long userId){
		if (userId==null) {
			return null;
		}

		logger.text("This should be remote service, will be with trace for user {}", userId);
		User user = new User();
		user.setId(123L);
		try {
			SimpleDateFormat simpleDateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
			user.setBirthday(simpleDateFormater.parse("2025-08-10T15:42:17.123+02"));
		} catch (ParseException e) {
			logger.exception(e);
		}
		user.setDriverLisenceId("a number that you can't know");
		user.setName("randome guy probably");
		return user;
	}
}

Sanitize logs

Specify Logging on methods through annotation:

package io.bitryon.example.web.service;

import org.springframework.stereotype.Service;

import io.bitryon.logger.Logger;
import io.bitryon.logger.annotation.Logging;
import io.bitryon.logger.provider.LoggerFactory;

@Service
public class SMTPEmailService {
	
	private static final Logger logger = LoggerFactory.getLogger();

	@Logging(sanitizerPatterns="*/MASK$3(recipient)", skipRandom=Integer.MAX_VALUE >>> 1)// mask the recipient JSON/*EmailService.sendByNoRepply*
	public String sendVerificationUrl(String recipient, String verificationUrl) {
		recipient = recipient.trim();
		String htmlContent = 
				  "<html><body>Please click on the <a href='"+verificationUrl+"'>link</a> "
				+ "or copy " + verificationUrl + " to your brower before it expires in 10 minutes.</body></html>";
		logger.text(htmlContent);// specially log it but still be count in the traces
		return htmlContent;
	}

}

Full logs

Some examples from the beginning:

2026-08-05T13:36:07.938Z||Z9z2xqC5hIKa3zYh||CONF||
[{
	"BootInfo": {
		"program": "1.2.2-1231321.jar",
		"region": "use-1",
		"version": "1.2.3",
		"external-ip": "12.2.2.2",
		"internal-ip": "12.2.2.2",
		"platform": {
			"cloud": "aws"
		}
	},
	"AppNodeConfig": {
		"httpHeaderIdType": 1,
		"applicationName": "bitryon-logging-java-spring-example",
		"hostId": "node-123.test.test"
	},
	"Github": {
		"host": "https://github.com/",
		"repository": "RepoOwner/bitryon-logging-java-spring-example",
		"branch": "master",
		"commit": "xxxxxxx",
		"sourcePaths": [
			"src/main/java"
		]
	},
	"LoggerConfig": {
		"fileName": "./logs/bitryon-logging-java-spring-example",
		"fileMaxLength": 536870912,
		"logDateTimeFormat": "yyyy-MM-dd HH:mm:ss.SSS",
		"loggerSchemaVersion": "1.0",
		"logLight": false,
		"logPretty": true,
		"printFile": true,
		"printStdout": true,
		"logAsync": true,
		"logSanitizerPatterns": [
			"/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)"
		]
	}
}]
2026-08-05 13:36:09.601|http-nio-80-exec-1#40|d21DXYk95tsqlA48XMszjqDyMbz0zesH|1|HTTP|
LoggingHttpRequestWebReader.java#io.bitryon.logger.spring.LoggingHttpRequestWebReader#readHttpRequest#31|
[null,{
	"remoteHost": "0:0:0:0:0:0:0:1:64498"
},{
	"method": "GET"
},{
	"requestURL": "http://localhost/api/user/save"
},{
	"headers": {}
},{
	"body": {
		"name": [
			"br***ng"
		],
		"driverLisenceId": [
			"6unq9XnrLfyeBSGpBVBftm"
		],
		"age": [
			"1001"
		]
	}
}]
2026-08-05 13:36:15.668|http-nio-80-exec-4#43|e4oPCb2nXz6lDwMFzW2YZYDTFlsbr7v5|5|JSON|
MedicService.java#io.bitryon.example.web.service.MedicService#save#48#|
[{
	"condition": {
		"id": 123,
		"deceases": "unko**",
		"timeCreated": "1970-01-01 00:00:00.0000",
		"userId": 0
	}
}]
2026-08-05 13:36:15.669|http-nio-80-exec-4#43|e4oPCb2nXz6lDwMFzW2YZYDTFlsbr7v5|6|JSON|
MedicDAO.java#io.bitryon.example.web.dao.MedicDAO#save#36#|
[{
	"condition": {
		"id": 123,
		"deceases": "unko**",
		"timeCreated": "1970-01-01 00:00:00.0000",
		"userId": 0
	}
}]
2026-08-05 13:36:15.670|http-nio-80-exec-4#43|e4oPCb2nXz6lDwMFzW2YZYDTFlsbr7v5|7|JSON|
MedicDAO.java#io.bitryon.example.web.dao.MedicDAO#save#36#R|
[{
	"id": 123,
	"deceases": "unko**",
	"timeCreated": "1970-01-01 00:00:00.0000",
	"userId": 0
}]
2026-08-05 13:36:15.670|http-nio-80-exec-4#43|e4oPCb2nXz6lDwMFzW2YZYDTFlsbr7v5|8|JSON|
MedicService.java#io.bitryon.example.web.service.MedicService#save#54|
[{
	"userId": 0
}]
2026-08-05 13:36:15.683|http-nio-80-exec-4#43|e4oPCb2nXz6lDwMFzW2YZYDTFlsbr7v5|9|JSON|
MedicService.java#io.bitryon.example.web.service.MedicService#save#54R|
[{
	"name": "ra***ly",
	"id": 123,
	"driverLisenceId": "WcReqeCH5tn7oeSNcfHyL1Ae04Q0waysU4hlSdiLtYZ",
	"age": null
}]
2026-08-05 13:36:15.683|http-nio-80-exec-4#43|e4oPCb2nXz6lDwMFzW2YZYDTFlsbr7v5|10|JSON|
MedicService.java#io.bitryon.example.web.service.MedicService#save#48#R|
[{
	"medicConditionDO": {
		"id": 123,
		"deceases": "unko**",
		"timeCreated": "1970-01-01 00:00:00.0000",
		"userId": 0
	},
	"user": {
		"name": "ra***ly",
		"id": 123,
		"driverLisenceId": "WcReqeCH5tn7oeSNcfHyL1Ae04Q0waysU4hlSdiLtYZ",
		"age": null
	}
}]

Workflow view

Finally, Sign-in and upload logs to portal for workflow-like view:

✨ Just like thatNow you own trinity observability.