기록되지 않음

내 블로그: https://sobolevn.me/2020/03/do-not-log
거의 매주 나는 의외로 이 일지 논쟁에 말려든다.문제는 사람들이 서로 다른 일을 기록하고 최선의 실천이라고 부르는 경향이 있다는 것이다.왜 그런지 모르겠어요.내가 다른 사람과 이 문제를 토론하기 시작했을 때, 나는 항상 같은 생각을 한 번 또 한 번 반복했다.
그래서오늘 나는 벌목 문화 전체를 비판하고 일련의 대체 방안을 제공하고 싶다.

로깅 의미 없음


가장 중요한 것부터 시작합시다.로그 기록은 아무런 의미가 없습니다!
인터넷에서 쉽게 볼 수 있는 유행 코드의 예를 살펴보겠습니다.
try:
    do_something_complex(*args, **kwargs)
except MyException as ex:
    logger.log(ex)
그럼, 이게 어떻게 된 일입니까?몇몇 복잡한 계산이 실패했으니, 우리는 그것을 기록할 것이다.이것은 마치 좋은 일인 것 같지 않습니까?좋아요.이런 상황에서 나는 보통 몇 가지 중요한 문제를 묻는다.
첫 번째 질문은 do_something_complex() 도달할 수 없는 대상을 위해 나쁜 상태를 만들 수 있습니까?만약 그렇다면, 코드를 재구성하여 유형 안전성을 가지도록 합시다.mypy에서 발생할 수 있는 모든 이상을 제거합니다.때때로 이것은 도움이 될 수 있다.이런 상황에서 우리는 어떠한 이상 처리와 로그 기록도 가지고 있지 않다.
두 번째 질문은 do_something_complex() 실패가 중요합니까?우리는 개의치 않는 경우가 많다.재시도, 대기열 또는 기타 이유로 건너뛸 수 있는 선택적 단계일 수 있습니다.만약 이 실패가 중요하지 않다면, 그것을 잊어라.하지만 이번 실패가 중요하다면 왜 실패했는지, 언제 실패했는지 확실하게 알고 싶다.전체 창고 추적, 국부 변수의 값, 실행 상하문, 실패 총수와 영향을 받은 사용자 수를 알고 싶습니다.나는 또 즉시 이 중요한 고장에 대한 통지를 받기를 바란다.클릭 한 번으로 이 실패에서 오류 탭을 만들 수 있습니다.
그래, 네가 맞혔어. 이건 벌목이 아니라 보초병의 일인 것 같아.

나는 안에 있는 모든 것에 대한 심각한 오류에 대한 빠른 통지를 원하거나, 아무것도 원하지 않는다. 조용한 아침, 차를 마시고, 유튜브 영상을 보자.이 둘 사이에는 아무런 로그 기록도 없다.
세 번째 문제는 우리가 응용 프로그램의 정상적인 작업을 확보하기 위해 업무 모니터링을 응용할 수 있느냐는 것이다.우리는 결코 이상과 그것을 어떻게 처리하는지에 진정으로 관심을 가지지 않는다.우리는 응용 프로그램의 상업적 가치에 관심을 갖는다.때때로, 당신의 프로그램은 보초병에게 잡히기 위해 어떤 이상도 일으키지 않는다.그것은 다른 방식으로 깨뜨릴 수 있다.예를 들어 폼 검증은 비정상적인 상황에서 오류를 되돌릴 수 있습니다.예외는 없지만 응용 프로그램의 기능이 정상적이지 않습니다.이것이 바로 업무 감시의 섬광점이다!

우리는 서로 다른 업무 지표를 추적하여 새로운 주문서, 새로운 평론, 새로운 사용자 등을 확보할 수 있습니다. 만약 그렇지 않다면 긴급 통지가 필요합니다.분노한 고객이 전화를 하거나 문자를 보낸 후, 나는 로그 정보를 읽는 데 추가 돈을 낭비하고 싶지 않다.사용자를 모니터링 서비스로 보지 마십시오!
마지막 질문은 보통 do_something_complex() 실패를 기대하십니까?예를 들어 HTTP 호출이나 데이터베이스 접근 등이다.의 경우 don't use exceptions 를 사용합니다.이런 방식을 통해 너는 어떤 일이 곧 실패할 것이라는 것을 분명히 나타낼 수 있다.자신 있게 행동하다.어떤 내용도 기록하지 마라.그냥 실패하게 합시다.

결과 목록 로그 기록은 일종의 부작용이다


더 중요한 것은monad와 관련된 주제는 내부에 기록기가 호출하는 함수의 순결성이다.두 개의 유사한 함수를 비교해 봅시다.
def compute(arg: int) -> float:
    return (arg / PI) * MAGIC_NUMBER
다음을 수행합니다.
def compute(arg: int):
    result = (arg / PI) * MAGIC_NUMBER
    logger.debug('Computation is:', result)
    return result
이 두 함수 간의 주요 차이점은 첫 번째는 완전 순함수이고, 두 번째는 IO계 불순 함수이다.
그것은 어떤 결과가 있습니까?
  • 반환 형식을 IOResult[float] 로 변경해야 합니다. 로그 기록이 순수하지 않아서 실패할 수 있습니다. (예, 로그 기록자가 실패하고 응용 프로그램을 파괴할 수 있습니다.)
  • 우리는 이런 부작용을 테스트해야 한다.우리는 이렇게 하는 것을 기억해야 한다.이 부작용이 반환 유형
  • 에 명확하게 나타나지 않는 한
    현명한 프로그래머는 심지어 스페셜 을 사용하여 로그 기록을 순수하고 명확하게 만든다.이것은 이 기능을 둘러싸고 전체 구조를 현저하게 바꿔야 한다.
    우리는 또한 정확한 Writer 실례를 전달하기를 희망할 수도 있다. 이것은 우리가 반드시 logger monad 명세서를 사용해야 한다는 것을 의미할 수도 있다.
    이 모든 추상적인 것에 대해 내가 말하고 싶은 것은 정확한 로그 체계 구조는 실현하기 어렵다는 것이다.이것은 단지 여기와 저기를 쓰는 것만은 아니다.이것은 복잡한 과정으로 적당한 추상을 만들고 그것들을 조합하며 엄격한 순수함과 불순한 코드층을 유지해야 한다.
    당신의 팀은 준비가 되었습니까?

    RequiresContext 기반 의존 주입 로깅은 하위 시스템입니다.


    우리는 과거에 종종 일을 문서에 기록했다.이거 재밌어!
    이런 간단한 설정이라도 로그 파일 회전을 정기적으로 해야 합니다.하지만 이것은 매우 쉽다.우리는 또한 logger.log() 을 사용하여 이 파일에서 내용을 찾습니다.하지만 그래도 우리에게는 문제가 있다.서버가 몇 개 있습니까?이 모든 파일과 grep 연결에서 필요한 정보를 찾으십시오.
    하지만 아직은 부족해!이 모든 마이크로 서비스,cloudnative와 다른 도구가 있으니, 우리는 로그 기록을 처리하기 위해 복잡한 하위 시스템이 필요합니다.포함 (단, 이에 국한되지 않음):
  • 큰뿔사슴:
  • ElasticSearch + Logstash + Kibana
  • 다음은 Graphana + Loki 큰뿔 사슴 더미로 이 일을 완성하는 절차입니다.
    version: '3.2'
    
    services:
      elasticsearch:
        build:
          context: elasticsearch/
          args:
            ELK_VERSION: $ELK_VERSION
        volumes:
          - type: bind
            source: ./elasticsearch/config/elasticsearch.yml
            target: /usr/share/elasticsearch/config/elasticsearch.yml
            read_only: true
          - type: volume
            source: elasticsearch
            target: /usr/share/elasticsearch/data
        ports:
          - "9200:9200"
          - "9300:9300"
        environment:
          ES_JAVA_OPTS: "-Xmx256m -Xms256m"
          ELASTIC_PASSWORD: changeme
          discovery.type: single-node
        networks:
          - elk
    
      logstash:
        build:
          context: logstash/
          args:
            ELK_VERSION: $ELK_VERSION
        volumes:
          - type: bind
            source: ./logstash/config/logstash.yml
            target: /usr/share/logstash/config/logstash.yml
            read_only: true
          - type: bind
            source: ./logstash/pipeline
            target: /usr/share/logstash/pipeline
            read_only: true
        ports:
          - "5000:5000/tcp"
          - "5000:5000/udp"
          - "9600:9600"
        environment:
          LS_JAVA_OPTS: "-Xmx256m -Xms256m"
        networks:
          - elk
        depends_on:
          - elasticsearch
    
      kibana:
        build:
          context: kibana/
          args:
            ELK_VERSION: $ELK_VERSION
        volumes:
          - type: bind
            source: ./kibana/config/kibana.yml
            target: /usr/share/kibana/config/kibana.yml
            read_only: true
        ports:
          - "5601:5601"
        networks:
          - elk
        depends_on:
          - elasticsearch
    
    networks:
      elk:
        driver: bridge
    
    volumes:
      elasticsearch:
    
    이거 너무 어려운 거 아니야?!봐라, 나는 단지 문자열만 쓰고 싶다 ssh.그리고 그것을 어딘가에 보관해라.
    하지만 아니에요. 데이터베이스가 필요해요.단독 웹 서비스와로그 서브시스템을 감시해야 합니다.정기적으로 업데이트를 하려면 안전해야 한다.그리고 충분한 자원이 있습니다.모든 사람이 그것을 사용할 수 있다.잠깐만, 잠깐만.
    물론 일부 클라우드 공급자는 로그 기록에만 사용된다.그것들을 사용하는 것을 고려하는 것은 아마도 좋은 생각일 것이다.

    하나의 예 로깅 관리가 어렵습니다.


    만약 이전의 모든 논쟁이 끝난 후에도 로그 기록을 사용하고 있다면, 많은 규정과 도구가 필요하다는 것을 알게 될 것입니다.모두가 알고 있는 몇 가지 문제가 있다.
  • 로그는 그 격식에 대해 매우 엄격해야 한다.NoSQL 데이터베이스에 로그를 저장할 수 있다는 것을 기억하십니까?우리의 로그는 색인이 필요합니다.최종적으로 또는 유사한 솔루션을 사용할 수 있습니다.내가 보기에 이것은 기본값일 것이다
  • 다음은 수평이다.모든 개발자들은 자신의 생각으로 어떤 것이 관건이고 어떤 것이 아닌지를 판단한다.당신이 stdout 를 쓰지 않으면 대부분의 사례를 포함한다.자세한 검사가 필요할 수도 있습니다.그렇지 않으면 로그 데이터베이스가 쓸모없는 데이터로 인해 붕괴될 수 있습니다

  • 로그 사용이 일치해야 합니다!
    모든 사람들은 자신의 풍격으로 글을 쓰는 경향이 있다.그리고 clear policy!다음 작업을 수행합니다.
    logger.info(
        'Hello {world}',
        extra={'world': 'Earth'},
    )
    
    대신:
    logger.info(
        'Hello {world}'.format(world='Earth'),
    )
    
  • 그리고 많은 다른 변두리 상황들
  • 로그는 업무를 대상으로 해야 한다.
    나는 보통 사람들이 로그 기록을 사용할 때 소량의 유용한 정보만 제공하는 것을 본다.예를 들어, 잘못된 현재 대상의 상태를 기록하고 있다면: 이것은 부족합니다!더 많은 작업을 해야 합니다. 이 대상이 어떻게 이런 무효 상태에 들어갔는지 보여 주어야 합니다.이 문제를 해결할 다른 방법이 있다.일부 사람들은 간단한 해결 방안을 사용한다. 예를 들어 a linter, 일부 사람들은 version history 변경에 따라 그들의 대상을 합성한다.일부 라이브러리는 실행 상하문, 채택된 논리적 절차, 그리고 대상에 대한 변경 사항을 기록한다.유사EventSourcing structlog .다음은 컨텍스트의 모양입니다.
  •    ApplyPromoCode.apply
         find_category
         find_promo_code
         check_expiration
         calculate_discount (errored: TypeError)
    
       Context:
         category_id = 1024                # Story argument
         category = <example.Category>     # Set by ApplyPromoCode.find_category
         promo_code = <example.PromoCode>  # Set by ApplyPromoCode.find_promo_code
    
    보이다그것은 발생한 일과 이 오류를 다시 만드는 방법에 대한 완전한 표시를 포함한다.무작위 상태 정보만이 아니다.너는 심지어 직접 로거에게 전화할 필요조차 없다.그것은 너를 위해 처리할 것이다.겸사겸사 한마디 하자면, 그것은 심지어 하나docs on logging까지 있는데, 이것은 내가 보기에 더욱 좋다.
  • 네가 기록한 내용에 주의해야 한다.
    당신의 로그에는 native Sentry integraion 와 전문적인 안전 감사가 있습니다.로그인 비밀번호, 신용카드, 이메일 등은 안전하지 않다는 것이 상식이다.안타깝게도 상식이 부족하다.이것은 복잡한 과정이다.
  • 또 다른 문제는 처리해야 한다.정책을 만들고 절차를 작성하며 로그 도구 체인을 설정하는 데 베테랑이 필요하다는 것을 보여 주십시오.

    GDPR 로그 규칙 어떡하지?


    빠르게 살펴보겠습니다.
  • 로그 기록은 감시와 오류 추적에서 큰 의미가 없다.더 좋은 도구로 바꾸기: 오류와 경보가 있는 업무 모니터링
  • 로그 기록은 당신의 구조에 매우 큰 복잡성을 증가시켰다.그것은 더 많은 테스트를 필요로 한다.구조 모드를 사용하여 로그 기록을 계약의 명확한 부분으로 만들기
  • 로그 기록 자체가 완전한 인프라 서브시스템이다.이것은 상당히 복잡한 문제다.이 작업을 유지하거나 기존 로그 서비스에 아웃소싱해야 합니다
  • .
  • 정확하게 기록해야 한다.이것은 매우 어렵다.너는 어쩔 수 없이 많은 공구를 사용할 것이다.너는 우리가 방금 토론한 문제를 의식하지 못한 개발자들을 지도해야 한다
  • 로그 기록이 가치가 있습니까?당신은 이러한 지식과 당신의 프로젝트 수요에 따라 현명한 결정을 내려야 합니다.내가 보기에, 대부분의 일반적인 웹 응용 프로그램은 그것을 필요로 하지 않는다.
    이거 맞혀주세요.나는 로그 기록이 매우 유용하다는 것을 안다. (때로는 유용한 정보의 유일한 출처이기도 하다.)예를 들어 내부 배치 소프트웨어와 같다.또는 프로그램이 완전히 실행되지 않았을 때 초기 절차를 밟으세요.만약 로그 기록이 없다면 무슨 일이 일어났는지 이해하기 어렵다.나는 일종의 과도한 블로그 문화와 싸우고 있다.일지가 이유 없이 사용될 때.개발자들은 원가와 평가를 분석하지 않고 개발을 하기 때문이다.
    너는 나에게 가입할 거니?

    좋은 웹페이지 즐겨찾기