콘텐츠로 이동

Logback Socket 로그 수집 모범 사례


소개

회사 입장에서 Guance 워크스페이스에는 여러 애플리케이션의 로그가 수집됩니다. 이러한 로그가 어떤 Service에서 발생했는지 구분하는 것이 문제입니다. 이제 Pipeline을 사용하여 로그에 Service 태그를 추가하여 로그 출처를 구분하는 방법을 살펴보겠습니다.
DataKit은 다양한 방식으로 로그를 수집합니다. 이 문서에서는 Java Springboot 애플리케이션에서 Socket을 통해 로그를 수집하고, Logback의 Socket을 통해 DataKit으로 로그를 전송하는 방법을 중점적으로 설명합니다. 먼저 운영자가 DataKit에서 Socket 수집기를 활성화하고 DataKit을 재시작합니다. 그런 다음 개발자가 애플리케이션의 logback-spring.xml 파일에 Appender를 추가하고 springProperty를 선언하여 jar를 시작할 때 Service 이름을 로그에 기록합니다. 그런 다음 개발자가 jar를 시작하고 로그에 기록할 Service 이름을 애플리케이션에 전달합니다. 마지막으로 개발자가 Guance에 로그인하여 로그 모듈의 Pipeline 탭 아래에서 새 Pipeline을 생성하고 운영자가 개설한 Socket 수집기의 Source를 지정합니다. 이렇게 하면 로그에 태그가 지정되어 구분됩니다.
아래 제공되는 솔루션은 개발자와 운영자의 관점에서 이 기능을 함께 구현합니다.

솔루션

운영자

Linux 환경

1 수집기 활성화

DataKit이 배포된 Linux 서버에 로그인하여 logging-socket.conf 파일을 추가합니다.

cd /usr/local/datakit/conf.d/log
vi logging-socket.conf

logging-socket.conf 파일 내용은 다음과 같습니다.

      [[inputs.logging]]
        # only two protocols are supported:TCP and UDP
        sockets = [
          "tcp://0.0.0.0:9542",
        #"udp://0.0.0.0:9531",                  
        ]
        ignore = [""]
        source = "socketdefault"
        service = ""
        pipeline = ""
        ignore_status = []
        character_encoding = ""
        # multiline_match = '''^\S'''
        remove_ansi_escape_codes = false

        [inputs.logging.tags]
        # some_tag = "some_value"
        # more_tag = "some_other_value"
2 DataKit 재시작
systemctl restart datakit

Kubernetes 환경

Guance에 로그인하여 【통합】->【Datakit】-> 【Kubernetes】에서 안내에 따라 DataKit을 설치합니다. 배포에 사용되는 datakit.yaml은 이후 수정이 필요합니다. 절차는 logging-socket.conf 파일을 생성하여 DataKit에 마운트하는 것입니다.

1 ConfigMap에 설정 추가
    logging-socket.conf: |-
      [[inputs.logging]]
        # only two protocols are supported:TCP and UDP
        sockets = [
          "tcp://0.0.0.0:9542",
        #"udp://0.0.0.0:9531",                  
        ]
        ignore = [""]
        source = "pay-socket-service"
        service = ""
        pipeline = ""
        ignore_status = []
        character_encoding = ""
        # multiline_match = '''^\S'''
        remove_ansi_escape_codes = false

        [inputs.logging.tags]
        # some_tag = "some_value"
        # more_tag = "some_other_value"
2 logging-socket.conf 마운트
        - mountPath: /usr/local/datakit/conf.d/log/logging-socket.conf
          name: datakit-conf
          subPath: logging-socket.conf
3 DataKit 재시작
kubectl delete -f datakit.yaml
kubectl apply -f datakit.yaml

파라미터 설명

  • sockets: 프로토콜 및 포트입니다.
  • ignore: 파일 경로 필터링으로 glob 규칙을 사용하며, 조건 중 하나라도 일치하면 해당 파일을 수집하지 않습니다.
  • source: 데이터 출처입니다.
  • service: 새로 추가된 태그입니다. 비어 있으면 기본적으로 $source를 사용합니다.
  • pipeline: Pipeline 사용 시 스크립트 경로를 정의합니다.
  • character_encoding: 인코딩을 선택합니다.
  • multiline_match: 여러 줄 매칭입니다.
  • remove_ansi_escape_codes: ANSI 이스케이프 코드(예: 표준 출력의 텍스트 색상 등)를 삭제할지 여부입니다. 값은 true 또는 false입니다.

개발자

1 의존성 추가

프로젝트의 pom.xml에 다음과 같이 의존성을 추가합니다.

<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>4.9</version>
</dependency>

2 로그 설정에 Appender 추가

이 단계에서는 DataKit 주소, Socket 포트, Service, Source를 외부에서 전달 가능한 파라미터로 정의합니다. 프로젝트의 logback-spring.xml 파일에 Appender를 추가하고 datakitHostIP, datakitSocketPort, datakitSource, datakitService를 정의하며, 값은 각각 guangce.datakit.host_ip, guangce.datakit.socket_port, guangce.datakit.source, guangce.datakit.service를 통해 외부에서 전달됩니다.

<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <springProperty scope="context" name="datakitHostIP" source="guangce.datakit.host_ip" />
    <springProperty scope="context" name="datakitSocketPort" source="guangce.datakit.socket_port" />
    <springProperty scope="context" name="datakitSource" source="guangce.datakit.source" />
    <springProperty scope="context" name="datakitService" source="guangce.datakit.service" />

    <contextName>logback</contextName>

    <!-- 로그 루트 디렉터리 -->
    <property name="log.path" value="./logs/order"/>
    <!-- 로그 출력 형식 -->
    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] -  - %msg%n" />

    <!-- 콘솔에 로그 출력 -->
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    ...

    <appender name="socket" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>${datakitHostIP:-}:${datakitSocketPort:-}</destination>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC+8</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                        "severity": "%level",
                        "source": "${datakitSource}",
                        "service": "${datakitService}",
                        "method": "%method",
                        "line": "%line",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "msg": "%message\n%exception"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="Console"/>
        ...
        <appender-ref ref="socket" />
    </root>
</configuration>

3 기본값 설정

application.yml 파일에 다음 설정을 추가합니다. 이러한 기본 파라미터는 Logback으로 전달됩니다.

guangce:
  datakit:
    host_ip: 127.0.0.1  # datakit 주소
    socket_port: 9542   # datakit socket 포트
    #source: mySource   # 주석 해제하지 않으면 socket 수집기에 정의된 source 사용
    #service: myService # 주석 해제하지 않으면 socket 수집기에 정의된 service 사용

4 애플리케이션 실행

1 Linux 환경

다음 명령을 실행하여 애플리케이션을 시작합니다. 파라미터를 전달하지 않으면 application.yml의 기본값이 사용됩니다.

java -jar  pay-service-1.0-SNAPSHOT.jar --guangce.datakit.host_ip=172.26.0.231 --guangce.datakit.socket_port=9542 --guangce.datakit.source=pay-socket-source --guangce.datakit.service=pay-socket-service
2 Kubernetes 환경

Dockerfile에 PARAMS를 추가하여 외부에서 전달되는 파라미터를 받습니다.

FROM openjdk:8u292
RUN echo 'Asia/Shanghai' >/etc/timezone


ENV jar pay-service-1.0-SNAPSHOT.jar
ENV workdir /data/app/
RUN mkdir -p ${workdir}
COPY ${jar} ${workdir}
WORKDIR ${workdir}
ENTRYPOINT ["sh", "-ec", "exec java ${JAVA_OPTS} -jar ${jar} ${PARAMS} 2>&1 > /dev/null"]
docker build -t 172.16.0.238/df-demo/istio-pay:v1 -f DockerfilePay .
docker push 172.16.0.238/df-demo/istio-pay:v1

pay-deployment.yaml 파일을 작성하고 PARAMS 환경 변수를 추가합니다. 여기서 guangce.datakit.host_ip, guangce.datakit.socket_port, guangce.datakit.source, guangce.datakit.service 값을 전달하며, 전달하지 않으면 기본값이 사용됩니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: istio-pay-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: istio-pay-pod
  template:
    metadata:
      labels:
        app: istio-pay-pod
    spec:
      containers:
      - env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: DD_AGENT_HOST
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.hostIP
        - name: PARAMS
          value: "--guangce.datakit.host_ip=$(DD_AGENT_HOST) --guangce.datakit.socket_port=9542 --guangce.datakit.source=pay-socket-source --guangce.datakit.service=pay-socket-service"

        name: pay-container
        image: 172.16.0.238/df-demo/istio-pay:v1
        ports:
        - containerPort: 8091
          protocol: TCP
        resources:
          limits: 
            memory: 512Mi
          requests:
            memory: 256Mi

      restartPolicy: Always
      volumes:
      - emptyDir: {}
        name: datadir
kubectl apply -f pay-deployment.yaml

5 Pipeline 구성

Socket Appender가 출력하는 로그는 JSON 형식이므로 DataKit은 Pipeline을 사용하여 JSON 문자열을 추출해야 합니다. source와 service는 기본 태그이므로 set_tag를 사용해야 합니다.
Guance에 로그인하여 【로그】->【Pipelines】에서 【Pipeline 생성】을 클릭하고 운영자가 Socket 수집기를 활성화할 때 정의한 source 이름인 socketdefault를 선택합니다. 다음과 같이 파싱 규칙을 정의합니다.

        json(_,msg,"message")
        json(_,class,"class")
        json(_,thread,"thread")
        json(_,severity,"status")
        json(_,method,"method")
        json(_,line,"line")
        json(_,source,"source")
        json(_,service,"service")
        json(_,`@timestamp`,"time")
        set_tag(service)
        set_tag(source)
        default_time(time) 

로그 샘플을 사용하여 테스트를 통과한 후 【저장】을 클릭합니다. 여기서의 파싱 규칙은 logback-spring.xml 파일에 추가된 pattern과 일치합니다.

                    <pattern>
                        {
                        "severity": "%level",
                        "source": "${datakitSource}",
                        "service": "${datakitService}",
                        "method": "%method",
                        "line": "%line",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "msg": "%message\n%exception"
                        }

로그 파일 확인

애플리케이션의 API에 접속하여 애플리케이션 로그를 생성합니다. Guance에 로그인하여 【로그】->【데이터 수집】-> pay-socket-source를 선택하고 로그 상세 정보를 확인합니다. 여기서 source와 service가 외부에서 전달된 파라미터로 대체된 것을 확인할 수 있습니다.

image

image

문서 평가

이 페이지가 도움이 되었나요?