티스토리 뷰

Grafana를 Terraform 으로 프로비저닝하기 전에 UI 에서 직접 설정을 해보자

1️⃣ Data Source

좌측 메뉴에서 Connections > Data sources 클릭한다.
Add new data source 버튼을 클릭한다.
loki를 검색하여 Loki를 선택한다.
URL에 Loki의 URL을 넣는다. (2편 보고 오면 ECS Service Connect로 Loki의 URL은 http://loki:3100 이다.)
하단의 Save & test 버튼을 클릭하고, connect 성공하면 다음과 같이 보여진다.

2️⃣ Dashboard

Connection 추가 후 나오는 building a dashboard 를 클릭하거나
좌측 메뉴에서 Dashboards 를 클릭하여
dashboard 를 새로 생성한다.
Add visualization 버튼을 클릭한다.
Select data source 에서 아까 추가해둔 Loki connection 을 클릭한다.
예시 Dashboard 가 보여지고, 우리가 원하는 Dashboard 를 만들어보자

  • 로그를 전부 보여주는 Dashboard

Label browser 버튼을 클릭한다.
로그를 확인하고 싶은 인프라를 설정하고, Show logs 버튼을 클릭한다.
쿼리를 LogQL 형태로 직접 넣어서 데이터를 추출할 수도 있다. 위에서 Builder 로 추출한 데이터와 결과는 같다.
Open visualization suggestions 를 클릭한다.
로그 형태는 이러하다.
테이블 형태는 이러하다.

  • Error 로그의 count 를 보여주는 Dashboard (Alert 만들기용)

Label browser 버튼을 클릭한다.
로그를 확인하고 싶은 인프라를 설정하고, Show logs 버튼을 클릭한다.
+ Operations 버튼을 클릭한다.
count 를 검색하여 Count over time 을 선택한다.
Range는 1m 으로 설정한다.
ERROR 가 포함된 로그만 경보를 쏠것이기 때문에 + Operations 버튼으로 Label filters > Label filter expression 을 선택하여 log 라는 Label 에 ERROR 가 포함되는지 검사하는 쿼리를 추가한다.
로그중에 INFO 로그 메시지에 ERROR 가 포함된 경우가 있어 INFO 로그는 제외하고 쏠수있게 추가 설정을 해주었다.
우측 Run query 버튼을 클릭하면 우리가 설정한대로 데이터가 추출된다.
쿼리를 LogQL 형태로 직접 넣어서 데이터를 추출할 수도 있다. 위에서 Builder 로 추출한 데이터와 결과는 같다.
대시보드 형태는 이러하다.

3️⃣ Alert

Alert Rules

저장된 대시보드에서
Alert rule 을 만들거나
좌측 메뉴에서 Alerting > Alert rules 를 클릭하여
Alert rule 을 만들 수 있다.
새로 Alert rule 을 생성하는 경우 위에서 Dashboard 를 생성했던 Query 를 Code 로 추가한다.
Expressions 설정에서 B Reduce 는 A에 들어온 Input 값을 조회하고, C Threshhold 는 B 에 들어온 Input 값이 0보다 큰지 조회하여 Alert 를 쏘게 설정한다.
저장할 폴더를 지정하고, Alert 를 쏘기까지 얼마동안의 기간동안 Pending 할지 시간을 적는다.
조회된 data 가 없는 경우 어떻게 취급할건지 설정한다. 우리의 경우 ERROR 데이터가 조회되지 않는 상황은 정상적인 상황이므로 OK 로 설정한다.
그밖에 Annotation 과 추가 Label 은 필요한 경우 설정해준다.
우측 상단의 Save rule and exit 버튼을 클릭한다.

Contact Points

  • 슬랙으로 경보를 쏴주어야 하기에 Slack Contact Point 를 만들어준다.

좌측 메뉴에서 Contact points를 클릭한다.
+ Add contact point 버튼을 클릭한다.
Integration에 Slack을 검색하여 선택한다.
Webhook URL에 슬랙의 Incoming Webhook 으로 얻은 웹훅 URL 을 붙여넣는다.
웹훅의 유저 이름, 타이틀, 내용, 멘션할 유저, 아이콘 등등 추가적인 세팅을 할 수 있다.
resolved message 는 경보로 받지 않는 설정을 한다.
Save contact point 버튼을 클릭하여 contact point 생성을 마친다.

  • 경보를 보낼 내용의 템플릿을 생성할 수 있다.

Contact points 에서 + Add template 버튼을 클릭한다.
Go 언어로 메시지 템플릿을 생성할 수 있다.

{{ define "Alert Instance Template" }}
에러 메시지 : {{ .Labels.log }}
{{ end }}

log Label 내에 있는 메시지를 경보 메시지에 포함하기 위한 메시지 템플릿 예시이다. 아래 Save template 버튼을 클릭한다.
위에서 생성한 Contact point (Slack) 에 Text Body 로 방금 생성한 message template 을 사진과 같은 형태로 넣어준다.

Notification Policies

Label 을 필터링하여 contact point 를 설정한다.

  • default 경보는 default contact point 로 쏘게 설정
  • Spring Boot 에서 발생한 로그에서 쏴야하는 경보의 경우 slack contact point 로 쏘게 설정
    • job = backend 인 경우 Slack 으로 설정

4️⃣ Spring Boot 에서 ERROR 로그 설정

원하는 대로 로그를 수집하고, 이를 통해 경보를 보내려면 로그를 수집하는 API Server 인 Spring Boot 코드에서도 설정이 필요하다.

Log 라는 Label 에 에러 메시지가 잘 들어가야 그를 경보로 쏠 수 있다.

  • logback-spring.xml 파일을 아래와 같이 수정해준다.
더보기
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <springProperty name="filePath" source="logging.file.path"/>
    <property name="LOG_PATTER"
              value="%d{HH:mm:ss.SSS} %-5level [File:%F] [Func:%M] [Line:%L] - %msg%n"></property>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTER}</pattern>
        </encoder>
    </appender>

    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/warn.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/warn-%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %-5level [File:%F] [Func:%M] [Line:%L] [Message:%m]- %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/error-%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %-5level [File:%F] [Func:%M] [Line:%L] [Message:%m]- %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>

    <logger name="com.example.demo.common" level="WARN">
        <appender-ref ref="WARN_FILE"/>
    </logger>

    <logger name="com.example.demo.domains" level="INFO"/>
    <logger name="com.example.demo.common" level="INFO"/>
    <logger name="com.example.demo" level="ERROR">
        <appender-ref ref="ERROR_FILE"/>
    </logger>

</configuration>
log.error("HttpClientErrorException has occured. %s %s %s".formatted(exception.getMessage(), exception.getCause(), exception.getStackTrace()[0]));
  • 실제로 error 로그를 쏘는 코드는 다음과 같이 작성한다.

5️⃣ 결과

다음과 같이 ERROR 로그가 발생하면 슬랙으로 경보가 날라온다.

6️⃣ 트러블슈팅

더보기
  • level=warn caller=client.go:419 id=0 component=client host=loki:3100 msg="error sending batch, will retry" status=429 tenant= error="server returned HTTP status 429 Too Many Requests (429): Maximum active stream limit exceeded, reduce the number of active streams (reduce labels or reduce label values), or contact your Loki administrator to see if the limit can be increased, user: 'fake'”
    • 테스트를 위해 00초에 한 번 로그를 쏘는 API Server 를 만들었었다.
    • 로그를 주기적으로 너무 많이 쏘니까 로봇이라고 판단해버린 이런 에러가 떴다.
  • failed to evaluate queries and expressions: [sse.readDataError] [A] got error: input data must be a wide series but got type long (input refid)
    • 경보를 만들기 위한 대시보드는 wide series 만 가능하다.
    • 경보 생성을 위한 대시보드는 rate 나 count 로 쿼리를 짜야 한다.
  • ERROR 로그가 없을 때에도 설정해둔 주기에 맞춰 DatasourceNoData 경보가 슬랙으로 계속 발송되었다.
    • Notification Policy 설정으로 default 경보는 default contact point 로 쏘게 하고 Spring Boot 에서 발생한 로그에서 쏴야하는 경보의 경우 slack contact point 로 쏘게 설정한다.
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함