응용 프로그램 로깅의 패턴과 패턴은 무엇입니까? [닫은]


66

최근 대기업 응용 프로그램의 현장 문제를 조사해야했습니다. 나는 문제를 찾기 위해 빗질해야한다는 통나무에 충격을 받았으며 하루가 끝나면 통나무가 버그를 식별 / 격리하는 데 전혀 도움이되지 않았습니다.

참고 : 모든 버그가 로그를 통해 발견되는 것은 아닙니다. 이것은 로그가 끔찍하다는 사실을 바꾸지 않습니다.

로깅에는 이미 수정하려고 시도 할 수있는 몇 가지 명백한 문제가 있습니다. 나는 여기에 그것들을 나열하고 싶지 않으며 단순히 우리의 로그 파일을 보여줄 수 없으므로 어떻게 해야할지에 대한 조언을 줄 수 있습니다.

대신, 우리가 벌목 전선에서 얼마나 나쁜지 평가하기 위해 다음과 같이 알고 싶습니다.

  1. 응용 프로그램, 특히 대규모 응용 프로그램에 대한 로깅 과 관련하여 지침 이 있다면 무엇입니까?
  2. 우리가 따라야 할 패턴 이나 반 패턴 이 있습니까?
  3. 이 해결해야 할 중요한 일 이나 그것도 고정 할 수 있습니다 또는 모든 로그 파일은 단순히 거대하고 당신이 그들을 분석하는 추가 스크립트를해야합니까?

참고 사항 : 우리는 log4j를 사용합니다.

답변:


55

내 연습이 유용하다는 몇 가지 사항 :

  • 모든 로깅 코드를 프로덕션 코드에 보관하십시오. 바람직하게는 서브 시스템 당 및 프로그램을 다시 시작하지 않고 프로덕션에서 더 많거나 적은 세부 로깅을 가능하게합니다.

  • 로그 grep를 눈으로 쉽게 파싱 할 수 있습니다. 각 줄의 시작 부분에 여러 공통 필드를 고수하십시오. 모든 라인에서 시간, 심각도 및 하위 시스템을 식별하십시오. 분명히 메시지를 공식화하십시오. 모든 로그 메시지를 소스 코드 라인에 쉽게 매핑 할 수 있습니다.

  • 오류가 발생하면 가능한 한 많은 정보를 수집하고 기록하십시오. 시간이 오래 걸릴 수 있지만 정상적인 처리에 실패 했으므로 괜찮습니다. 디버거가 연결된 프로덕션 환경에서 동일한 조건이 발생할 때까지 기다릴 필요가 없습니다.

로그는 주로 모니터링 및 문제 해결에 필요합니다. 문제 해결사의 신발에 몸을 맡기고 잘못된 일이 있거나 밤에 일어 났을 때 어떤 종류의 로그를 갖고 싶은지 생각해보십시오.


10
이 답변이 마음에 들지만 결정 지점에서 어떤 선택을했는지 기록하는 것이 중요하다고 덧붙입니다. 많은 정크가 기록되었지만 주요 결정이 기록되지 않은 많은 시스템을 보았습니다. 따라서 로깅의 95 %는 기본적으로 쓸모가 없습니다. 또한 요청 / 응답 유형 시스템의 경우 서브 시스템보다 요청 당 로그를 기록하는 것이 더 중요합니다.
Kevin

4
+1. 문제 해결 도구를 사용하는 것에 대해 말씀하신 것이 좋습니다. 그것은 우리가하고있는 것보다 훨씬 더 좋은 품질의 메시지를 포함하는 로그 설명처럼 들린다.
c_maker

1
오류 로그는 응용 프로그램 로그뿐만 아니라 적절한 이벤트 로그에도 기록되어야합니다.
Steven Evers

2
@SnOrfus : 로그를 저장하는 방법은 여러 가지가 있지만, 본질적으로 항공기 블랙 박스와 같이 시스템이 충돌 한 마지막 순간까지 로그 메시지를 사용할 수 있어야합니다. 버퍼링을 사용하는 경우이를 무시하고 모든 메시지를 플러시하는 옵션을 제공하십시오.
rwong

1
@Rig : 반면에, 자체 개발 한 많은 로거는 버퍼링을 구현하지 않았고 (모든 메시지를 충실하게 플러시) 성능이 매우 떨어졌습니다. 이것이 옵션으로 만들어야하는 이유입니다.
rwong

28

나는 안전에 중요한 실시간 시스템으로 작업하고 로깅은 종종 보름달이 될 때마다 53 번째 화요일마다 푸른 달에 한 번 나타나는 희귀 한 버그를 잡을 수있는 유일한 방법입니다. 이런 종류의 주제에 대해 강박 관념을 느끼게되므로 입에서 거품이 나기 시작하면 사과하겠습니다. 다음은 네이티브 코드 디버그 로그 용으로 작성되었지만 대부분 관리되는 세계에도 적용됩니다.

텍스트 로그 파일을 사용하십시오. 명백한 것처럼 보이지만 일부 사람들은 이진 로그 파일을 생성하려고 시도합니다. 현장에있을 때 리더 도구를 찾을 필요가 없기 때문에 바보입니다. 또한 텍스트이고 디버그가 장황한 경우 현장 엔지니어가 파일을 읽고 다시 돌아 오지 않고도 문제를 진단 할 수 있습니다. 모두가 이깁니다.

나는 거의 모든 것을 기록 할 수있는 시스템을 설계하지만 기본적으로 모든 것을 켜지는 않습니다. 디버그 정보는 숨겨진 디버그 대화 상자로 전송되어 타임 스탬프되어 목록 상자에 출력되며 (삭제하기 전에 약 500 줄로 제한됨) 대화 상자에서 정보를 중지하거나 로그 파일에 자동으로 저장하거나 연결된 디버거 이 전환을 통해 여러 응용 프로그램의 디버그 출력을 모두 깔끔하게 직렬화하여 볼 수 있으며 때로는 생명을 구할 수 있습니다. 내가 사용하는 숫자 로깅 수준 (높은 당신이 레벨을 설정은, 더 캡처) 사용 :

off
errors only
basic
detailed
everything

그러나 이것은 너무 융통성이 없습니다-버그로 나아가는 과정에서 많은 양의 이물질을 처리하지 않고도 필요한 것에 정확하게 집중할 수있어 훨씬 더 효율적이며, 특정 종류의 거래 또는 운영 일 수 있습니다 오류가 발생합니다. 만약 모든 것을 켜야한다면, 당신은 자신의 일을 더욱 어렵게 만드는 것입니다. 더 세밀한 것이 필요합니다.

이제 플래그 시스템을 기반으로 로깅으로 전환하는 과정에 있습니다. 기록되는 모든 것은 어떤 종류의 작동을 나타내는 플래그를 가지고 있으며, 기록되는 것을 정의 할 수있는 체크 박스가 있습니다. 일반적으로 해당 목록은 다음과 같습니다.

#define DEBUG_ERROR          1
#define DEBUG_BASIC          2
#define DEBUG_DETAIL         4
#define DEBUG_MSG_BASIC      8
#define DEBUG_MSG_POLL       16
#define DEBUG_MSG_STATUS     32
#define DEBUG_METRICS        64
#define DEBUG_EXCEPTION      128
#define DEBUG_STATE_CHANGE   256
#define DEBUG_DB_READ        512
#define DEBUG_DB_WRITE       1024
#define DEBUG_SQL_TEXT       2048
#define DEBUG_MSG_CONTENTS   4096

이 로깅 시스템은 릴리스 빌드 와 함께 제공 되며 기본적으로 설정되어 파일로 저장됩니다. 평균 6 개월에 한 번만 버그가 발생하고이를 재현 할 방법이 없다면 버그가 발생한 후에 로깅을해야한다는 것을 알기에는 너무 늦었습니다. 디버그 빌드에서만 작동하는 로깅은 간단합니다. 평원. 우둔한.

소프트웨어는 일반적으로 ERROR, BASIC, STATE_CHANGE 및 EXCEPTION이 켜져있는 상태로 제공되지만 디버그 대화 상자 (또는 레지스트리 / ini / cfg 설정이 저장되는 경우)를 통해 필드에서 변경할 수 있습니다.

아 그리고 한 가지-내 디버그 시스템은 하루에 하나의 파일을 생성합니다. 요구 사항이 다를 수 있습니다. 그러나 디버그 코드 는 날짜, 실행중인 코드 버전 및 가능한 경우 고객 ID, 시스템 위치 등을 나타내는 모든 파일을 시작해야합니다 . 현장에서 들어오는 로그 파일을 엉망으로 만들 수 있으며 실제로 데이터 자체에있는 시스템의 위치와 버전을 기록하고 고객을 신뢰할 수없는 기록이 필요합니다. / field engineer는 가지고있는 버전을 알려줍니다. 생각했던 버전을 알려줄 수 있습니다. 더 나쁜 것은 디스크에있는 exe 버전을보고하지만 이전 버전은 교체 후 재부팅을 잊었 기 때문에 여전히 실행 중입니다. 코드 자체를 알려주십시오.

마지막으로, 코드가 자체 문제를 생성하는 것을 원하지 않으므로 타이머 기능을 사용하여 며칠 또는 몇 주 후에 로그 파일을 제거하십시오 (지금 시간과 파일 생성 시간의 차이를 확인하십시오). 이것은 항상 실행되는 서버 응용 프로그램에 적합하며, 시작할 때 이전 데이터를 제거하여 얻을 수있는 클라이언트 응용 프로그램에서 얻을 수 있습니다. 일반적으로 엔지니어가 자주 방문하지 않는 시스템에서는 30 일 정도 후에 제거합니다. 분명히 이것은 로그 파일의 크기에 따라 다릅니다.


1
+1 일반적으로 훌륭한 대답이지만 특히 응용 프로그램 ID 및 버전 정보를 로그 파일에 넣는 경우 불행히도 자주 놓치는 부분입니다.
이진 걱정

27

로깅 가이드 라인에서 내가 가장 좋아하는 공개 리소스는 Apache JCL Best Practices 입니다.

JCL 모범 사례는 일반 및 엔터프라이즈의 두 가지 범주로 제공됩니다. 일반적인 원칙은 매우 분명합니다. 엔터프라이즈 관행은 조금 더 복잡하며 왜 중요한지 명확하지 않습니다.

엔터프라이즈 모범 사례 원칙은 "엔터프라이즈"레벨 환경에서 실행될 것으로 예상되는 미들웨어 구성 요소 및 툴링에 적용됩니다. 이러한 문제는 국제화로 로깅 및 오류 감지와 관련이 있습니다. 엔터프라이즈에는 더 많은 노력과 계획이 필요하지만 프로덕션 레벨 시스템에서는 (필요하지 않은 경우) 강력히 권장됩니다. 기업 / 환경에 따라 요구 사항이 다르므로 항상 유연성을 유지하면 도움이됩니다.

JCL을 대상으로 함에도 불구하고, 일반적으로 로깅에 채택 할 수있을 정도로 일반적인 것으로 보입니다.

  • 로깅에 대한 개인적인 "지침"은 디버그 수준에서 로그를 스토리처럼 읽도록 이해하는 것입니다. 이해하기 쉬운 논리와 충분한 (하지만 과부하되지 않은) 세부 사항이 있습니다.

가장 유명한 안티 패턴은 아마도 "예외 삼키기"일 것입니다. 웹에서 검색하십시오.

거대한 로깅 파일의 경우 내 연습에서 이것은 대부분 일반적인 경우입니다. 그리고 네, 보충 스크립트전기 톱 과 같은 도구 도 나에게 평범하게 보입니다.

  • 위의 내용이 모든 로그를 하나의 거대한 파일에 맹목적으로 배치해야한다는 의미는 아닙니다. 때로는 일부 로그를 별도의 파일에 쓰거나 복사하는 것이 유용 할 수 있습니다. 예를 들어 최근 프로젝트에서 QA 직원은 메트릭 및 타이밍 데이터와 시스템 운영에 대한 간단한 보고서를위한 전용 파일을 요청했습니다. 그들은 그로부터 이익을 얻을 것이라고 말했다. 그리고 개발자는 그것을 해냈다 (간단한 보고서 파일의 이점은 실제로 중요 함).

추신. 안티 패턴과 관련하여 마음에 떠오르는 다른 사람들은 "홍수"하고 의미없는 메시지입니다.

  • 반복이 많은 루프에서 여러 개의 유사한 메시지가 나오는 것을 범람 이라고합니다 . 나에게 홍수는 소스 코드에서 그것을 발견했을 때 그것을 없애려고 충분히 성가시다. 루프 내에서 일어나는 일들이 흥미로울 수 있기 때문에 일반적으로 그것을 개선하려면 약간의 예술이 필요합니다. 심층적으로 개선 할 시간이 없으면 필터링하기 쉽도록 최소한 이러한 메시지의 로깅 수준을 가장 낮은 수준으로 변경하려고합니다.

  • 무의미한 메시지 는 꽤 인기있는 쓰레기 인 것 같습니다. 소스 코드에서 읽을 때 무해한 것으로 보입니다. 디버그 출력을 분석하는 데 어려움을 겪어야한다고 생각합니다 ...

    step #1
    step #2
    step #3
    

    고유의 추악함을 깊이 인식합니다. 소스 코드 수준에서 이러한 종류의 문제를 감지하는 가장 좋아하는 휴리스틱 (이전 프로젝트 중 하나에서 동료가 제안한)은 로깅에 사용 된 문자열 리터럴에서 공간 기호 발생 수를 계산 하는 것입니다. 필자의 경험에 따르면 0 공간은 기본적으로 로깅 문이 의미가 없으며 1 공간은 잠재적 인 문제를 나타내는 좋은 지표입니다.


4
범람을 피하기 위해 보통 루프의 휴리스틱을 수집하고 루프 후에 출력합니다. 루프에서 흥미로운 일이 발생하면 의미있는 변수에 저장 somethingSpecialHappenedCount한 다음 로거로 출력해야합니다.
Spoike

@Spoike 좋은 지적! 변수에 저장하는 것은 실제로 홍수와 싸우기 위해 개인적으로 가장 좋아하는 트릭 중 하나입니다.
gnat

1
루프가 끝나면 로그에 ASCII 테이블로 모든 다른 카운터를 로거에 출력하여 쉽게 비교할 수 있습니다. 테이블 아이디어는 Spring의 StopWatch.prettyPrint ()가 생성 한 아이디어에서 영감을 받았습니다 . 그 외에, 로그 텍스트를 읽기 쉽고 관련성있게 만드는 것은 여전히 ​​앞서 언급 한 "예술"입니다.
Spoike

@Spoike : (그리고 @gnat) 이것은 흥미 롭습니다. 기본적으로 로깅 목적으로 비즈니스 로직에 실제 코드를 추가합니까? 나는 이것에 대해 들어 본 적이 없거나 전에 이것을 해본 적이 없으며 동료들에게 어떻게 그것을 정당화 할 것인지 확신하지 못합니다. 이 작업을 시작하면 일부 개발자가 비즈니스 로직이 복잡하고 읽기 어려워 질 정도로 소스 코드를 어지럽 힐 것 같습니다. 단순히 명령문을 로깅하면 이미 소스가 더보기 흉하게 보입니다.
c_maker

2
@c_maker 로깅과 비즈니스 로직을 혼합하는 것에 대한 요점은 전념해야 할 가치가 있습니다. 개인적으로 나는이 문제들에 대해 아직 강한 의견을 가지고 있지 않습니다. 이론적으로 AOP와 iirc를 사용한 분리 개선이 있다고 생각할 수 있습니다. 그러나 실제로는 "혼합"접근 방식을 사용하며 지금까지는 큰 문제가 없었습니다. 어수선한 소스 코드는 매우 위험하지만 다시 한 번, 로깅 코드와 "평화롭게"공존 할 수있었습니다. 물론 이것은 특정한 노력이 필요합니다.
gnat

11

예외를 한 번만 기록하십시오!

내가 목격 한 일반적인 문제점 중 하나는 예외를 기록하고 다시 던지는 것입니다. 결과적으로 로그 파일에는 여러 스택 수준에서 동일한 예외가 여러 번 포함됩니다.


5

반 패턴은 다음과 같습니다. 데이터베이스 테이블에 24 개의 "일반 변수"필드를 만들어 상상할 수있는 모든 것을 추적 한 다음 다양한 유형의 로그에 대해 서로 다른 열거 형 값을 갖는 88 (및 계산).


+1-나는 이것을 보았다. string1, string2, string3, string4, string5와 같은 열이있는 "오류 테이블". 모든 열을 연결하면 문서에서 참조되지 않은 오류 코드가 발생합니다. 결과는 혼란스럽고 쓸모없는 로깅입니다. "제 3 자 기업용 앱이있는 사용자 지정 개발 디버깅 지옥"이라고도합니다.
Morgan Herlocker

내 경우는 "기록이 실제로 포함 것의 어떤 생각없이 손으로 압연 로깅 시스템을"의
웨인 몰리나

4

로그에 대한 나의 경험이 클수록 나아지 지만 컴퓨터로 필터링 할 수있을 정도로 일관성이 있으며 응용 프로그램의 모든 구성 요소에 대해 심각도 수준을 개별적으로 구성 할 수 있습니다.

또한 향후 버그를 찾기 위해 어떤 로깅이 필요한지 예측하기가 매우 어렵습니다. 버그를 기록하기위한 대부분의 명백한 장소는 제품이 출시되기 전에 수정되었습니다. 버그 보고서의 결과가 다시 발생하는 경우이를 진단하기 위해 로깅을 추가 한 것이 드문 일이 아닙니다.


2

집안의 운영 측면에서 몇 가지 메모 :

1) 로그를 로컬로 구성 할 수 있는지 확인하십시오. 텍스트 편집기보다 무거운 도구를 사용하는 것이 좋습니다. 대부분의 경우 TRACE 수준 로깅을 원하지 않지만이 기능을 켜는 것을 좋아합니다.

2) 가능하면 텍스트 편집기보다 무거운 도구를 사용하여 로그를 읽을 수 있는지 확인하십시오. 생산 시스템이 고장날 때 이상한 시간에 공구 사냥을하는 것보다 더 나쁜 것은 없습니다.


1

내 자신의 웹 응용 프로그램 작업 경험에서 :

(현재 스토리지가 매우 저렴하다는 점을 고려하면)

  • 가능한 한 많은 정보 (그 순간)를 기록하십시오.
  • 항상 로그 문자열에 DateTime.Now를 포함시킵니다.
  • 나는 항상 (가능한 경우) 특정 "조치"의 시간을 기록합니다.
  • 로그 문자열과 일관성을 유지하십시오. 항상 이런 종류의 패턴을 사용하기 때문에 :

    • "[정보 X] [정보 Y] [정보 Z] [등]"

1

스택 추적 외에도 현재 응용 프로그램 상태와 입력을 기록합니다.

소프트웨어는 결정 론적이며,이 두 가지가 일반적으로 버그를 재현하는 데 필요한 유일한 것입니다. 전체 상태를 저장하면 문제가 될 수 있으므로 이전 입력과 같은 현재 상태를 재현하는 방법도 좋습니다.

물론 더 많은 데이터가 항상 더 좋지만 최소한이 두 가지가 가장 쉬운 충돌을위한 좋은 시작입니다.


3
"소프트웨어는 결정 론적입니다" => 불행히도 항상 그런 것은 아닙니다. 예를 들어 동시성 버그를 생각해보십시오.
assylias
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.