개발자의 오르막

[Log4j 1.2.16-ver Json Layout 적용기 #03] Logstash - jsonevent-layout 라이브러리 적용 본문

Java

[Log4j 1.2.16-ver Json Layout 적용기 #03] Logstash - jsonevent-layout 라이브러리 적용

계단 2022. 7. 11. 14:33

Logstash 의 Jsonevent-layout 이란?

Logstash 의 jsonevent-layout 은 log4j를 위한 json Layout Format 을 지원하는 라이브러리이다.

log4j 에서는 로그 레이아웃을 지원하기 위해 Appender 형식을 사용하는데, Jsonevent-layout 은 log4j 의 Appender 를 커스텀하여 지원한다.

log4j.appender.uploadProcessFile.layout=net.logstash.log4j.JSONEventLayoutV1

따라서 우리는 log4j 의 1.x.x version 을 그대로 사용하면서 logstash 가 지원하는 JsonLayout 을 log4j Appender 로 사용할 수 있다.

 

 

추가 라이브러리

 jsonevent-layout-1.7.jar  json-smart-2.3.jar  asm-1.0.2.jar  common-lang-2.6.jar

 

 

log4j.properties 적용방법

log4j.logger.UploadProcessLog = INFO, uploadProcessFile

log4j.appender.uploadProcessFile.Threshold = INFO
log4j.appender.uploadProcessFile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.uploadProcessFile.File = logs/upload-process.log
log4j.appender.uploadProcessFile.DatePattern=.yyyy-MM-dd
log4j.appender.uploadProcessFile.layout=net.logstash.log4j.JSONEventLayoutV1
  • 요구사항에 맞게 기존 Log 파일은 그대로 두되, 고객 업로드 감지에 대한 과정만 기록하는 JsonFormat 로그파일을 작성할 수 있도록 설정하였다.
  • Threshold 는 자세한 데이터보다는 업로드 과정만을 보여주기 때문에 로그 레벨을 INFO 로 설정하였다.
  • 매일 로그파일을 생성할 수 있도록 DailyRollingFileAppender 를 사용하였고, 신규 파일로 로그를 저장하기 위해 logs/upload-process.log 로 지정하였다.
  • 그리고 logstash 의 Jsoneventlayout 을 연동시켜주었다.

 

 

Json format 로그 메시지 예시

{
"@timestamp":"2022-07-15T07:28:34.762Z",
"source_host":"DESKTOP-NQ55UGN",
"file":"CommonUtils.java",
"method":"moveToWorkDir",
"level":"INFO",
"line_number":"850",
"thread_name":"DefaultQuartzScheduler_Worker-1",
"@version":1,
"logger_name":"UploadProcessLog",
"message":"WORK File Info Send Http Server STEP",
"class":"net.catenoid.watcher.upload.utils.CommonUtils",
}

 

upload-process.log 파일 출력 형태 예시

{"level":"INFO ","timestamp":"2022-07-11 11:16:40","thread":"main","file":"UploadProcessMsg.java", "method":"infoJsonLog", "line":"35","message":"WORK File Info Send Http Server STEP"}
{"level":"INFO ","timestamp":"2022-07-11 11:16:43","thread":"main","file":"UploadProcessMsg.java", "method":"infoJsonLog", "line":"35","message":"WORK File Info Send Http Server STEP"}

 

 

UploadProcessLogDto 생성

public class UploadProcessLogDTO {

    private UploadMode uploadMode;
    private String currentStep;
    private String totalStep;
    private String stepName;
    private String description;
    private String title;
    private String contentProviderKey;
    private String physicalPath;
    private String uploadPath;
    private String uploadFileKey;
    private ContentInfoDTO mediaInfo;

    public UploadProcessLogDTO(UploadMode uploadMode, String currentStep, String stepName,
                               String description, ArrayList<FileItemDTO> files) {
        this.uploadMode = uploadMode;
        this.currentStep = currentStep;
        this.totalStep = getTotalStep(uploadMode);
        this.stepName = stepName;
        this.description = description;
        if (files.size() > 0) {
            this.contentProviderKey = getContentProviderKey(files);
        }
    }
    
    public String getJsonLogMsg() {
        putMdcUploadInfo();
        return this.stepName;
    }
		...
}
  • 최초 UploadProcessLog 구현체를 생성하여, 위의 소스처럼 UploadProcessLogDto Logger 를 생성, 해당 구현체에만 의존성을 지니게 하려하였지만, 로그가 찍히는 위치가 구현체 내부로 일관되다보니 , 효용성이 많이 떨어지게 되었다.
    • 어디 위치에서 log 가 찍혔는지, error 가 찍혀는지 알 수 있어야한다.

 

 

 

  • 따라서 로그가 찍히는 클래스파일에 아래와 같은 Logger 를 별도 생성하였다.
private static Logger uploadProcessLog = Logger.getLogger("UploadProcessLog");
  • 그 후 위의 Dto 인스턴스를 생성하여, 우리가 찍고자하는 Json 형태의 String 을 uploadProcessLog 에 주입하면, JSON 형태의 로그가 출력된다.
UploadProcessLogDTO step1Msg = new UploadProcessLogDTO(
					UploadMode.FTP, "1", "Ls Parsing New File Items STEP", 
					"Ls parsing file cnt : " + files.size()  + ", dirs cnt : " + dirs.size(), 
					files);
uploadProcessLog.info(step1Msg.getJsonLogMsg());

 

JSON MSG 로 로깅하기

JSONLayoutV1 을 통해 Log 메시지를 JSON Format 으로 제공할 수 있었다. 하지만 Message 에 들어가는 정보 또한 String 이 아닌 JSON 형태로 제공하는 것이 필요했다.

 

log4j2 에서는 org.apache.logging.log4j.message.ObjectMessage 을 제공하여 ObjectMessage 객체를 생성해 로그로 던지면 손쉽게 Json Message 를 출력할 수 있으나, log4j-1.x.x 에서는 제공하지 않는다.

 

따라서 log4j-1.x.x 에서도 지원하는 MDC ( Mapped Diagnostic Context ) 를 활용하여 Map 의 형태로 로깅을 지원하였다.

 

UploadProcessLogDto

private void putMdcUploadInfo() {
        MDC.clear();

        MDC.put("uploadMode", this.uploadMode);
        MDC.put("currentStep", this.currentStep);
        MDC.put("totalStep", this.totalStep);
        MDC.put("description", hasText(this.description) ? this.description : "");

        if (hasText(this.contentProviderKey)) {
            MDC.put("contentProviderKey", this.contentProviderKey);
        }
        if (hasText(this.title)) {
            MDC.put("title", this.title);
        }
        if (hasText(this.uploadPath)) {
            MDC.put("uploadPath", this.uploadPath);
        }
        if (hasText(this.physicalPath)) {
            MDC.put("physicalPath", this.physicalPath);
        }
        if (hasText(this.uploadFileKey)) {
            MDC.put("uploadFileKey", this.uploadFileKey);
        }
}

 

MDC Log 출력 형태

"mdc":{
   "currentStep":"4-1",
   "totalStep":"5",
   "contentProviderKey":"jungin-kim",
   "description":"move from \/home\/kollus\/upload\/jungin-kim\/_None\/sample.webm to \/mnt\/medianas\/working\/jungin-kim",
   "uploadMode":"FTP",
   "physicalPath":"\/home\/kollus\/upload\/jungin-kim\/_None\/sample.webm",
   "title":"sample",
   "uploadFileKey":"DSFDS123SDFDS",
   "uploadPath":"\/jungin-kim\/_None\/sample.webm",
   "mediaInfo":{
      "imageWidth":null,
      "videoRatio":"1.778",
      "imageFormat":null,
      "videoFormat":"AVC",
      "rotation":"0",
      "format":"Matroska",
      "audioFormat":"Opus",
      "videoFrameRate":null,
      "audioCodec":null,
      "audioBitrate":null,
      "audioSampleRate":"48000",
      "imageHeight":null,
      "videoHeight":"720",
      "duration":null,
      "videoBitrate":null,
      "videoWidth":"1280",
      "videoDuration":null,
      "scanType":null,
      "audioDuration":null,
      "videoCodec":null
   }
}

 

 

 

 

 

 

Reference

 

Comments