레이블이 log인 게시물을 표시합니다. 모든 게시물 표시
레이블이 log인 게시물을 표시합니다. 모든 게시물 표시

filebeat kafka out of acceptable range

log 수집용 filebeat pod 하나가 계속 높은 CPU 사용량을 보인다.
로그를 보면
{"log.level":"error","@timestamp":"2026-04-07T08:12:32.206+0900","log.logger":"kafka","log.origin":{"function":"github.com/elastic/beats/v7/libbeat/outputs/kafka.(*msgRef).dec","file.name":"kafka/client.go","file.line":446},"message":"Kafka publish failed with: kafka server: The timestamp of the message is out of acceptable range","service.name":"filebeat","ecs.version":"1.6.0"}

pod 를 재시작해도 시간이 좀 지나면 다시 CPU 사용량이 90%를 넘어간다.

kafka publish 실패 -> 재시도 무한 반복 -> CPU 급증

broker 레벨 timestamp 설정 확인
kafka-configs --bootstrap-server 카프카호스트:9092 --entity-type brokers --describe --all | rg -i timestamp

log.message.timestamp.type=CreateTime (체크 대상 타입)
log.message.timestamp.after.max.ms=3600000 (1시간, 메시지 시간이 이 시간보다 1시간 초과시 거부)
log.message.timestamp.before.max.ms=9223372036854775807 (사실 무제한, 과거 메시지 모두 허용)

메시지 timestamp 가 before / after 를 벗어난 경우 kafka broker가 timestamp 범위 초과로 메시지를 거부한다.
kafka timestamp 설정은 이상이 없어 보인다.

filebeat.yml 설정에 max_retries가 명시되어 있지 않아 디폴트 3으로 사용된다.
output.kafka:
    enabled: true
    hosts: "${kafka_hosts}"
    topic: "%{[@metadata][topic]}"
    partition.round_robin:
      reachable_only: false
      group_events: 1

max_retries 회수가 제한이 있는데도 CPU가 안 떨어진다는 건 처리해야 할 오래된 로그 라인 자체가 엄청나게 많다는뜻일 수 있다.
registry 초기화 후 모든 로그 파일을 처음부터 다시 읽으면서
이벤트마다 전송 시도 -> 실패 -> retry 3번 (backoff 포함) -> drop -> 다음 이벤트 -> 또 실패
이 사이클이 수십만 건 이상 반복되고 있을 수 있습니다. 시간이 충분히 지나면 결국 CPU는 내려가겠지만, 로그 양이 많으면 오래 걸릴 수 있습니다.

당장 해결을 위해선 pod 재시작 한다.
pod 재시작 후 에도 같은 현상이면 container 상에서 registry(active.dat, log.json, 12345.json)을 지우고 재시작하자. 이때 meta.json 을 지우면 pod 재시작시 crash 가 발생하니 유지해야 된다.
실수로 삭제했다면 meta.json 는 이런 내용으로 다시 생성하면 된다.
{"version":"1"}

filebeat 수집 대상이 *.log* 로 되어 있어 로그 로테이션으로 log 파일들도 매칭이 되고 있는게 근본적인 원인으로 보여 *.log* -> *.log 패턴으로 수정했다.

terminated screencapture

맥스크린 캡쳐시 저장이 안되는 경우가 발생했다. 될 때는 되고 안될때는 안되던가 수초간의 딜레이가 발생 후 저장됐다
스크린 캡쳐 관련 프로세스는 다음 2개가 있다.
screencapture: cmd+shift+3/4 로 실제로 캡처를 수행하는 프로세스
screencaptureui: cmd+shift+5 로 화면 캡처 메뉴 UI 를 보여주는 프로세스

위 2개 프로세스를 모니터링(btop 등에서 screen 이름으로 필터링) 하고
cmd+shift+4 누르면 screencapture 가 실행되고 종료되지만 캡쳐가 되지 않거나 느리게 캡쳐된다.

다음과 같은 명령으로 영역 캡쳐 테스트시 캡쳐가 안되는 경우 강제 종료가 되고 있다는것을 알았다.
screencapture -R 0,0,100,100 -t jpg z.jpg
zsh: terminated  screencapture -R 0,0,100,100 -t jpg z.jpg

cmd+shift+5 누르면 screencaptureui 가 생겼다 사라진다.(메뉴가 잠깐 보였다 사라진다)
screenshot.app 앱도 실행하면 켭쳐메뉴가 바로 종료된다.
claude-code 으로 원인 파악을 해봤다.

screencaptureui(PID: 37344) 로그를 모니터링하면
/usr/bin/log show --last 2m | grep "37344" | grep -i "exit"

launchd가 프로세스 종료 시 자동으로 기록하는 로그에 원인이 포함되어 있었다.
launchd: [gui/501/com.apple.screencaptureui.agent [37344]:] exited due to SIGTERM | sent by TouchEN_TEWeb_Agent[854], ran for 285ms

원인은 TouchEN_TEWeb_Agent(금융/보안 프로그램)이였다.
TEWebUNInstall.pkg 를 실행해서 삭제하니 잘된다.

observability data pipeline - vector

# kubernetes(k8s) pods stdout,stderr 는 노드의 다음에 경로에 저장된다.
/var/log/pods
/var/log/containers (pods 하위 컨테이너 로그 파일들이 이곳에 링크로 걸려 있음)

# 이런 pod 로그들을 예전에는 fluentd 에서 정재 -> es / kafka 로 보냈는데,
# 요즘에는 fluentd 대신 vector(observability data pipeline - agent & aggregator) 를 많이 사용하는것 같다.
# rust 로 만들어서인지 안정성과 성능이 좋은것 같다. 

# helm 으로 설치
helm repo add vector https://helm.vector.dev
helm repo update

# helm value 설정
# vector 는 다음 3가지 형태(role)로 배포 할 수 있다.
# agent: daemonset 으로 모든 노드의 data(stdout)를 수집
# sidecar: 파드별 pod에 사이드카로 vector 를 띄워 pod에 대해서만 수집
# aggregator: 다른 스트림으로 부터 입력(수집) 
# customConfig 로 디폴트 설정을 대신할 수 있다.
# configmap > data 설정된다.
# kubernetes_logs,host_metrics,internal_metrics(source) -> transform -> prometheus_exporter,console(sink) 로 소비하는 흐름
cat << zzz > values.yaml
role: Agent
customConfig:
  data_dir: /vector-data-dir
  api:
    enabled: true
    address: 127.0.0.1:8686
    playground: false
  sources:
    kubernetes_logs:
      type: kubernetes_logs
    host_metrics:
      filesystem:
        devices:
          excludes: [binfmt_misc]
        filesystems:
          excludes: [binfmt_misc]
        mountpoints:
          excludes: ["*/proc/sys/fs/binfmt_misc"]
      type: host_metrics
    internal_metrics:
      type: internal_metrics
  sinks:
    prom_exporter:
      type: prometheus_exporter
      inputs: [host_metrics, internal_metrics]
      address: 0.0.0.0:9090
    stdout:
      type: console
      inputs: [kubernetes_logs]
      encoding:
        codec: json
zzz

# 설치 하면 Agent 면 daemonset 으로 worker/ingress 노드들에 vector pod 가 설치된다.
helm install vector vector/vector --namespace vector --create-namespace --values values.yaml

# vector 버전업 반영시
helm repo update
helm upgrade vector vector/vector --namespace vector --values values.yaml

# vector 삭제시
helm uninstall vector --namespace vector

# vector 처리 현황 보기
kubectl -n vector exec -it daemonset/vector -- vector top --url http://127.0.0.1:8686/graphql

# k8s log -> filter -> remap -> kafka,elasticsearch,console 로 보내는 경우
# console 은 vector pod log 에서 확인
# vi values.yaml
role: Agent
customConfig:
  data_dir: /vector-data-dir
  api:
    enabled: true
    address: 127.0.0.1:8686
    playground: false
  sources:
    k8s_log:
      type: kubernetes_logs
      # namespace 가 kube_system 아닌것 중 ysoftman 인 것만
      extra_field_selector: metadata.namespace=!kube_system,metadata.namespace=ysoftman
  transforms:
    k8s_transform1:
      type: filter
      inputs:
        - k8s_log
      condition: .level != "debug"
    k8s_transform2:
      type: remap
      inputs:
        - k8s_transform1
      source: |
        # % root of the event metadata
        # . root of the event
        # set es index name
        %custom_type = "sample"
        if .message == r'.*error.*' {
          # % root of the event metadata
          %custom_type = "error"
        }
  sinks:
    kafka_log:
      type: kafka
      inputs: [k8s_transform2]
      bootstrap_servers: logis-kafka-dev.daumtools.com:9092
      topic: ysoftman-dev-sample
      encoding:
        codec: json
    es_log:
      type: elasticsearch
      inputs:
        - k8s_transform2
      endpoints:
        - http://ysoftman.es:9200
      bulk:
        index: "ysoftman-sample-%Y-%m-%d"
    console_log:
      type: console
      inputs: [k8s_transform2]
      encoding:
        codec: json

# 다음 명령으로 VRL(Vector Remap Language) 스크립트를 실행/확인해볼 수 있다.
# 입력 프롬프트가 뜨면 아래와 같이 테스트
vector vrl

# 공백/콜론 제거 예시
$ parse_regex!("A : B", r'^(?P<first>\w+)[\s:]+(?P<second>\w+)$')
{ "first": "A", "second": "B" }

# 공백/콜론 제거 리턴으로 값 가져오는 예시
$ parsed, err = parse_regex("A : B", r'^(?P<first>\w+)[\s:]+(?P<second>\w+)$')
{ "first": "A", "second": "B" }

$ parsed
{ "first": "A", "second": "B" }

$ err
null

ssh 로그인 후 바로 종료 문제

# k8s pod 내에 sshd -D 를 기동 후
# 다음과 같이 ssh 연결을 하면 바로 연결이 close 된다.
ssh root@localhost -vvv

... 생략 ...
Last login: Sat Apr 29 07:38:26 2023 from 127.0.0.1
debug3: receive packet: type 96
debug2: channel 0: rcvd eof
... 생략 ...
Connection to localhost closed.
debug1: Exit status 255

# receive packet : type 96(SSH_MSG_CHANNEL_EOF)으로
# 보통 연결된 ssh 에서 exit/logout 하면 받는 패킷이다.

# lastlog(/var/log/lastlog) 로 마지막 로그를 봐도 로그인 된 흔적이 있다.
Username         Port     From             Latest
root             pts/3    127.0.0.1        Sat Apr 29 07:38:28 +0000 2023
... 생략 ...

# lastb(/var/log/btmp)로 실패한 로그인 기록은 보면 없다고 나오고
# last(/var/log/wtmp) | head -2 로 성공한 로그인 기록을 보면 내역에도 기록 되어 있다.
# 그런데 로그인 후 바로 로그아웃되었다.
root     pts/3        127.0.0.1        Sat Apr 29 07:38 - 07:38  (00:00)
root     pts/3        127.0.0.1        Sat Apr 29 07:38 - 07:38  (00:00)

# 혹시 root 기본 쉘을 확인해보면 bash 정상
cat /etc/passwd | grep groot
root:x:0:0:root:/root:/bin/bash

# ssh closed 시 verbose 내용에 255 종료상태가 있는것을 보고 
# 체크1
# 로그인시 ~/.profile, ~/.bashrc 를 rename 으로 로딩을 하지 않아도 closed 된다.

# 체크2
# root/.ssh/ 에 있는 environment 파일이 다른 정상 container 와 달리 꽤 커서 살펴봤다.
# pod(container)의 파일을 로컬로 복사
kubectl cp {namespace}/{pod_name_ssh_접속정상}:/root/.ssh/environment ./environment1
kubectl cp {namespace}/{pod_name_ssh_접속문제}:/root/.ssh/environment ./environment2

# environment1 파일은 500라인인데, environment2 파일은 1000라인이다.
# 문제가 있는 container /root/.ssh/environment 의 내용을 라인을 지워가면서 접속 여부를 확인해봤다.
# 확인결과 environment 내용에 상관없이 라인수를 991로 줄이면 접속이 성공한다.
# 접속시 너무 많은 environment 설정(현재 client 와 중복도 많이 되고 있었음) 문제였음...

k8s pod log tool stern

# stern 커맨드를 사용하면 k8s 의 n 개의 pod 로그를 한번에 볼수 있다.
# ysoftman 네임스페이스의 aaa 이름(정규표현 가능) 로그 보기
stern "aaa" -n ysoftman

# 전체 네임스페이스에서 aaa 이름(정규표현 가능) 로그 보기
stern "aaa" -A

# 전체 네임스페이스에서 aaa 이름(정규표현 가능) 로그 보기
# 로그 중 json 포맷만 보기, jq 로 포맷팅해서 보면 좋다.
stern "aaa" -A -o json | jq

docker log size per line

# 도커 로깅에서 stdout 한줄의 길이가 16K 로 제한되어 있다고 한다.
# 관련해서 설정을 변경하는 PR 있었지만 진행되지 않았음.

access log - get null 400 에러

# tomcat 에러 중 다음과 같이 path 부분이 null 이 찍히는 경우가 있다.
# 참고로 로그는 apache httpd mod_log_config 를 사용한다.
https://httpd.apache.org/docs/2.4/ko/mod/mod_log_config.html

# /var/lib/tomcat8/conf/server.xml 에서 로그 포맷 설정
# %{Foobar}i - Foobar 헤더
# %h - 원격 호스트
# %l - 원격 identid가 제공한 로그인명, 기본값(-)
# %u - 원격 auth가 제공한 사용자명, 기본값(-)
# %t - 표준 영어 시간
# %r - 요청 첫번째 줄
# %s - 상태코드
# %b - http 헤더를 제외한 전송 바이트 수
# %h %l %u %t "%r" %s %b 포맷

# tomcat access log 확인
sudo tail -f /var/log/tomcat8/localhost_access_log.2019-01-31.txt

# 브라우저에서 '아이유' 요청하면 URL 인코딩 되고 다음과 같이 정상 동작(로깅)
127.0.0.1 - - [31/Jan/2019:18:15:30 +0900] "GET /%EC%95%84%EC%9D%B4%EC%9C%A0 HTTP/1.1" 404 1110

# curl 로 다음처럼 한글이 URL인코딩 없이 요청하는 경우 null 로 되고
# tomcat server.xml 의 protocol 기본 설정이 HTTP/1.1 로 돼있어
# HTTP/1.0 을 사용해도 로그에 HTTP/1.1 로 기록된다.
curl "http://localhost:8080/아이유" --http1.0 -s > /dev/null

# path 가 null 로 되어 처리할 수 없게 된다.
127.0.0.1 - - [31/Jan/2019:18:15:30 +0900] "GET null HTTP/1.1" 400 800

# tomcat 에러 로그를 확인을 위해 모든 로그를 확인해보자.
sudo vi /var/lib/tomcat8/conf/logging.properties
java.util.logging.ConsoleHandler.level = ALL

# tomcat 재시작
sudo service tomcat8 restart

# 에러 로그를 확인해보면
sudo tail -f /var/log/tomcat8/catalina.out

java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

# 관련 내용을 구글링 해보니 tomcat 7.0.73, 8.0.39, 8.5.7 이상에서 발생하고
# http connector 에 relaxedQueryChars 를 설정하라고 한다.
https://stackoverflow.com/questions/41053653/tomcat-8-is-not-able-to-handle-get-request-with-in-query-parameters

# tomcat 버전 확인하면 8.5.30.0 이다.
sudo bash /usr/share/tomcat8/bin/version.sh

# 다음과 같이 특수문자를 처리해봤지만 한글 utf8코드는 처리 되지 않았다.
sudo vi /var/lib/tomcat8/conf/server.xml

<Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;" />

# relaxedQueryChars 특수문자는 명시할 수 있지만 non-alphabet 범위의 문자코드는 어떻게 명시할 방법이 없어, client 가 URL 인코딩을 해줘야 한다.

nginx rotate log

# 방법1
https://www.cambus.net/log-rotation-directly-within-nginx-configuration-file/
# 하지만 error.log 에는 적용이 안된다.
# nginx.conf 설정
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})") {
    set $year $1;
    set $month $2;
    set $day $3;
    set $hour $4;
    set $minutes $5;
}
access_log /var/log/nginx/$year-$month-$day-$hour-$minutes-access.log;

# 방법2
https://www.nginx.com/resources/wiki/start/topics/examples/logrotation/
http://nginx.org/en/docs/control.html#logs
# USR1 시널을 사용해 로그 파일 모두 rotate 가능하다.
# 쉘 스크립트를 작성해서 크론잡으로 등록한다.
# 1시간 전의 시간으로 파일명 변경
mv access.log `date -d '1 hour ago' '+%Y-%m-%d-%H-%M'`-access.log

# nignx 마스터 프로세스에 USR1(file reopen) 시그널 보내기
kill -USR1 `cat master.nginx.pid`
sleep 1

# 로그레벨 참고 : debug, info, notice, warn, error, crit, alert, emerg
error_log logs/error.log 로그레벨;

# 방법3
# logrotate 사용(nginx 외 일반적인 로그들에 모두 사용 가능)
https://github.com/logrotate/logrotate
# centos logrotate 설치
yum install logrotate

# ubuntu(debian) logrotate 설치
apt-get install logrotate

# logrotate 는 cron 으로 실행 주기를 관리한다.
# logrotate 기본 설정
vi /etc/logrotate.conf

# 설정 파일들 위치 포함
include /etc/logrotate.d

# nginx logrotate 설정
vi /etc/logrotate.d/ysoftman_nginx

# /var/log/nginx/*.log 파일은
/var/log/nginx/ {
    # 매일 로그를 바꾼다. 매주는 weekly, 매월은 monthly
    daily

    # 4일 분량의 로그를 남긴다. weekly 라면 4일, monthly 라면 4월
    rotate 4

    # 로그 파일이 비워있으면 로테이션 하지 않는다.
    notifempty

    # 로그파일이 유실되더라고 에러를 발생시키지 않는다.
    missingok

    # 로테이션후 빈파일을 생성
    create

    # 로테이션된 파일의 suffix 로 날짜지정 (xxx.log-YYMMDD)
    dateext

    # 압축하기
    compress

    # 모든 로그파일에 대해서 postrotate 스크립트가 한번만 실행되도록(공유) 한다.
    sharedscripts

    # postrotate ~ endscript 사이에는 로테이션 후 실행될 쉘 스크립트 명시
    postrotate
       kill -USR1 `cat /home/ysoftman/nginx/master.nginx.pid`
    endscript 
}

# 테스트 해보기
# logrotate 는 로테이션 된 내역을 다음 파일로 기록한다.
# 여기에 기록된 파일들은 로테이션 되지 않는다.
# 테스트를 위해 logrotate 필요하다면 파일명 뒤에 있는 rotate 시간을 과거로 수정한다.
# 이파일은 삭제하더라도 logrotate 실행하면 다시 이전 상태로 복구되니 시간을 수정해야 한다.
cat /var/lib/logrotate/logrotate.status

# debug(실제 rotate 는 되지 않음)모드로 테스트
# 실행 작업 순서가 출력지만 실제 rotate 할때는 에러가 발생할 수 있다.
logrotate -d /etc/logrotate.d/ysoftman_nginx

# 실제 rotate 해보기
# compress 등 rotate 후의 작업이 실행이 되지 않았다면
# -v 로 postrotate 등의 스크립트 에러 메시지를 체크해 보자.
logrotate -v /etc/logrotate.d/ysoftman_nginx

apache httpd log rotation

Apache httpd 로그파일이 시간이 갈수록 커지는데 일정 시간/사이즈로 파일을 분리하여 관리 할 수 있다.(log rotation)
apache httpd rotatelogs 설명
https://httpd.apache.org/docs/2.4/ko/programs/rotatelogs.html

apache httpd 로그 설명
https://httpd.apache.org/docs/2.4/ko/logs.html

##########

# rotatelogs 를 사용하는 경우
# Apache httpd 에서는 rotatelogs 를 제공한다.
# 이를 이용하면 특정 시간/사이즈 마다 로그 파일을 분리(백업)할 수 있다.
vim httpd.conf

# 24시간마다 로그 파일 구분
CustomLog "|bin/rotatelogs /www/logs/accesslog 86400" common

# 5M 크기가 넘어서면 로그 파일 구분
ErrorLog "|bin/rotatelogs /www/logs/error%Y%m%d%H%M.log 5M"


##########

# cronolog 를 사용하는 경우
# cronolog 는 yymmdd 등의 템플릿 설정에 따라 로그 파일을 구분한다.
# 맥에서 설치
brew install cronolog

# centos 에서 설치
sudo yum install cronolog
vim httpd.conf

# 현재 시간으로 로그 파일 구분
CustomLog "|/usr/sbin/cronolog /www/logs/access%Y%m%d%H%M.log"

# 심볼릭 링크를 추가하는 경우
ErrorLog "|/usr/sbin/cronolog -S /www/logs/error.log /www/logs/error%Y%m%d%H%M.log"

웹 액세스 로그 시각화 툴 LogStalgia

apache, nginx 와 같은 웹 서버의 accesslog 를 visualization(시각화)해주는 툴이다.
윈도우, 리눅스, 맥 모두에서 동작한다. (콘솔환경은 안됨)
다운로드 http://logstalgia.io/

# 로그파일 기준으로 플레이(실행)
logstalgia access.log

# 실시간으로 시각화 하기
tail -f /var/log/apache2/access.log | logstalgia --sync

logstash 윈도우 서비스로 등록하기

logstash 를 윈도우 서비스로 등록하기 위해서 sc 를 사용한경우 서비스가 등록되지만 시작시 에러가 발생한다.
이럴땐 nssm 이라는 서비스 매니저 유틸리티를 사용하자.
다운로드 http://nssm.cc
nssm.exe 파일만 있으면된다.

[서비스 등록]
nssm.exe install logstash c:\logstash\bin\start-logstash.bat

[서비스 삭제]
nssm.exe remove logstash

[start-logstash.bat 내용]
@rem ysoftman
@rem logstash 윈도우 서비스로 등록하기
@rem set LS_MAX_MEM=256m
cd "c:\logstash\bin"
logstash.bat agent -f sendlog.conf

Linux 로그 보기

# 리눅스 로그 파일은 보통 /var/log 에 파일로 기록된다.
# 로그 파일은 스트링과  바이너리 형식이며 바이너리인 경우 last 명령으로 세부 기록 사항을 파악 할 수 있다.
# 로그인/로그아웃 기록
last -f /var/log/wtmp.1

# 현재 시스템을 사용하고 있는 사용자 기록
last -f /var/run/utmp

# 시스템 로그
last -f /var/log/syslog.1

# 시스템 이벤트 로그
vi /var/log/messages

# 부팅시 로그(-e 이벤트 실제 날짜로 표시)
dmesg -e
# 또는
vi /var/log/dmesg

Prev