feat: 운영 서비스 1차 Observability 구축 - #33
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive observability and telemetry pipeline for the Mapleland production environment. It replaces direct Loki4j logging with structured ECS logging to local files, which are then collected by Grafana Alloy alongside host and application metrics. It also secures the Prometheus actuator endpoint using a custom security filter with bearer token authentication, adds a custom binder for process resident memory metrics, and configures Grafana dashboards and alert rules. The reviewer identified a potential NullPointerException in the newly introduced SafeExceptionLog utility if a null throwable is passed, which should be addressed to ensure robust error logging.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive observability pipeline for the Mapleland application, migrating from direct Loki4j logging to Spring Boot's native ECS structured logging with local file rotation, and setting up Grafana Alloy to scrape metrics and tail logs. It adds a loopback-bound management server secured by a bearer token, custom Linux RSS memory metrics, a robust exception sanitization utility, and extensive deployment, validation, and runbook documentation. The review feedback is highly valuable and should be addressed: first, add a null check in SafeExceptionLog.addException to prevent a potential NullPointerException; second, optimize the filter chain order in SecurityConfig to ensure the Prometheus scrape token filter runs before JWT authentication filters to avoid malformed token exceptions.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
관련 Issue
결과
Spring Boot 애플리케이션과 OCI VM의 1차 Observability를 구현하고 운영에 적용했습니다.
949976f0fd46ff60094c54e5b3df8433a6e4de59dba0494107d196e9acd564b3b7d4f229b8d91f64(운영 증거와 logical/live resource 구분만 보완한 docs-only commits)successmerge는 별도 요청 전 수행하지 않습니다.
설계 결정
/var/log/mapleland-api/mapleland-api.json에 JSON Lines로 기록합니다. Boot 전체 업그레이드는 하지 않았습니다.:8080의/actuator/**는 404입니다. Management:18080은 host127.0.0.1publish 전용이고 Prometheus는 bearer 인증을 요구합니다. Alloy:12345도127.0.0.1전용입니다.service_name,deployment_environment,level,cloud_provider네 개뿐입니다. logger/thread/event/HTTP/error/trace/request/mapleland field는 structured metadata 또는 ECS body에 둡니다.deploy/observability/grafana/에서 버전 관리합니다. Grafana Cloud가 file provisioning wrapper를 직접 받지 않으므로 live alert는 기존 로그인 UI에서 동일 query/threshold로 만들었습니다.자동 검증
successsuccess./gradlew clean test bootJar --no-daemon, 47 tests, failure/error/skipped 0fmt --test와validate성공git diff --check검증운영 적용
sha256:0560502466a7b54f2bea0596e1963f68197e1bb085be42d99cd17ae959409875; 운영 container RepoDigest와 일치sha256:1b9b13b75debfe76ad755f618738bd63972a270b78d03f90d50133ee277fa3afrollback-20260716T105725955628686-1b9b13b75deb-351732; 최종 배포에서 rollback은 실행되지 않음running, restart count 0,SERVICE_VERSION은 운영 commit과 일치8080과 Traefik/firewall은 변경하지 않았습니다. 새 port18080,12345는 loopback 전용입니다./var/log/mapleland-deploy/last-failure와 검증 fixture는 성공 확인 뒤 제거했습니다.Behavioral evidence
애플리케이션·보안 경계
/api/v1/jobs200:8080의/actuator/prometheus,/actuator/health,/actuator/env,/actuator/configprops모두 404GRAFANA_CLOUD_*환경변수 0개ECS 로그·Alloy
observability.stack-trace-testfixture 1건이 Loki에서 정확히 한 event로 표시됐고error.type/message/stack_trace,event.action/outcome이 조회됨. Newline은 JSON 문자열 안에 escape됨. 애플리케이션에 운영 예외를 유발하지 않았고 fixture는 제거함.event_action집계는 2건active/enabled/ready; app 로그 파일 ACL과 rotation 후 read 권한 유지Grafana Cloud
UP; 30회 smoke 후 request rate와 p50/p95 실제 sample 렌더링Mapleland(live UIDfnp4gz), groupMapleland Production, interval 1mNormalNormalNormalgrafana-default-emailcontact point와 default notification policy/route는 변경하지 않음성능·Free Tier
max(20%, 5ms)이내instance=mapleland-oci-1; Loki에는 host label을 추가하지 않음Secret 처리
/etc/alloy/alloy.env에서만 읽습니다./opt/mapleland/ghcr.env의 allowlisted key만 strict parser로 읽습니다..env.exampleplaceholder만 있고 실제 token/credential은 없습니다.롤백
--pull never --force-recreate로 복구하고 image ID, public smoke를 재검증systemctl disable --now alloy; package rollback은 checksum 확인 → unmasked/stopped 설치 → installed binary validate → explicit start/ready전체 명령과 health/smoke/data-arrival/복구 절차는
docs/observability-runbook.md, 최종 무비밀 운영 상태는docs/observability-rollout-checkpoint.md에 있습니다.범위 밖·후속 위험
maxLifetime정합성 후속 조사 필요