Python용 OpenTelemetry 시작하기

관찰 가능성은 출력을 검사하여 시스템의 내부 상태를 측정하는 기능입니다. 출력의 정보, 즉 센서 데이터만 사용하여 현재 상태를 추정할 수 있는 경우 시스템은 "관측 가능"한 것으로 간주됩니다.
마이크로서비스의 맥락에서 관찰 가능성을 통해 팀은 다음을 수행할 수 있습니다.
  • 최신 시스템을 보다 효과적으로 모니터링
  • 복잡한 체인에서 효과를 찾아 연결하고 원인을 역추적합니다
  • .
  • 전체 아키텍처에 대한 시스템 관리자, IT 운영 분석가 및 개발자의 가시성을 활성화합니다
  • .

    가시성의 3가지 기둥


  • 메트릭 - 메트릭은 시간 간격 동안 측정된 숫자 값이며 타임스탬프, 이름, KPI 및 값과 같은 특정 속성을 포함합니다. 로그와 달리 메트릭은 기본적으로 구조화되므로 스토리지를 쿼리하고 최적화하기가 더 쉬워지므로 메트릭을 더 오래 보관할 수 있습니다.
  • 로그 - 로그는 특정 시간에 발생한 이벤트의 텍스트 레코드이며 이벤트 발생 시점을 알려주는 타임스탬프와 컨텍스트를 제공하는 페이로드를 포함합니다. 로그는 일반 텍스트, 구조화 및 바이너리의 세 가지 형식으로 제공됩니다
  • .
  • 추적 - 추적은 분산 시스템을 통한 요청의 종단 간 여정을 나타냅니다. 요청이 호스트 시스템을 통해 이동함에 따라 요청에서 수행되는 모든 작업("스팬"이라고 함)은 해당 작업을 수행하는 마이크로 서비스와 관련된 중요한 데이터로 인코딩됩니다.
    각각 하나 이상의 범위를 포함하는 추적을 보면 분산 시스템을 통해 경로를 추적하고 병목 현상이나 고장의 원인을 식별할 수 있습니다.

  • Documentation source


    Python을 사용한 계측

    간단한 플라스크 서버부터 시작하겠습니다.

    $ pip install flask
    



    import datetime
    import flask
    
    ######################
    ## initialization
    ######################
    app = flask.Flask(__name__)
    start = datetime.datetime.now()
    
    ######################
    ## routes
    ######################
    @app.route('/', methods=['GET'])
    def root():
      return flask.jsonify({'message': 'flask app root/'})
    
    @app.route('/healthz', methods=['GET'])
    def healthz():
      now = datetime.datetime.now()
      return flask.jsonify({'message': f'up and running since {(now - start)}'})
    
    if __name__ == '__main__':
      app.run(debug=True, host='0.0.0.0', port=5000)
    


    OpenTelemetry(otel) 라이브러리를 추가해 보겠습니다.

    $ pip install opentelemetry-api opentelemetry-sdk
    


    이제 계측을 시작하고 추적을 추가하고 횟수를 계산하기 위한 지표/healthz를 호출합니다.

    import datetime
    
    import flask
    from opentelemetry import trace
    from opentelemetry import metrics
    
    ######################
    ## initialization
    ######################
    app = flask.Flask(__name__)
    start = datetime.datetime.now()
    
    tracer = trace.get_tracer(__name__)
    meter = metrics.get_meter(__name__)
    
    hltz_counter = meter.create_counter('healthz_count', description='Number of /healthz requests')
    
    ######################
    ## routes
    ######################
    @app.route('/', methods=['GET'])
    def root():
      return flask.jsonify({'message': 'flask app root/'})
    
    @app.route('/healthz', methods=['GET'])
    def healthz():
      now = datetime.datetime.now()
      hltz_counter.add(1)
      return flask.jsonify({'message': f'up and running since {(now - start)}'})
    
    if __name__ == '__main__':
      app.run(debug=True, host='0.0.0.0', port=5000)
    


    계측된 코드 실행

    $ opentelemetry-instrument --traces_exporter console --metrics_exporter console flask run
     * Debug mode: off
    WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
     * Running on http://127.0.0.1:5000
    ...
    


    약간의 트래픽 통과

    $ curl localhost:5000
    {"message":"flask app root/"}
    
    $ curl localhost:5000/healthz
    {"message":"up and running since 0:00:53.605913"}
    


    터미널을 관찰하고 healthz_count를 확인합니다.

    127.0.0.1 - - [13/Oct/2022 09:16:54] "GET / HTTP/1.1" 200 -
    127.0.0.1 - - [13/Oct/2022 09:16:58] "GET /healthz HTTP/1.1" 200 -
    {
        "name": "/healthz",
        "context": {
            "trace_id": "0x7d30b2042efe9a4661cc427352119754",
            "span_id": "0x479211d157c16733",
            "trace_state": "[]"
        },
        "kind": "SpanKind.SERVER",
        "parent_id": null,
        "start_time": "2022-10-13T03:50:31.090144Z",
        "end_time": "2022-10-13T03:50:31.090545Z",
        "status": {
            "status_code": "UNSET"
        },
        "attributes": {
            "http.method": "GET",
            "http.server_name": "127.0.0.1",
            "http.scheme": "http",
            "net.host.port": 5000,
            "http.host": "localhost:5000",
            "http.target": "/healthz",
            "net.peer.ip": "127.0.0.1",
            "http.user_agent": "curl/7.79.1",
            "net.peer.port": 50286,
            "http.flavor": "1.1",
            "http.route": "/healthz",
            "http.status_code": 200
        },
        "events": [],
        "links": [],
        "resource": {
            "attributes": {
                "telemetry.sdk.language": "python",
                "telemetry.sdk.name": "opentelemetry",
                "telemetry.sdk.version": "1.13.0",
                "telemetry.auto.version": "0.34b0",
                "service.name": "unknown_service"
            },
            "schema_url": ""
        }
    }
    {"resource_metrics": [{"resource": {"attributes": {"telemetry.sdk.language": "python", "telemetry.sdk.name": "opentelemetry", "telemetry.sdk.version": "1.13.0", "telemetry.auto.version": "0.34b0", "service.name": "unknown_service"}, "schema_url": ""}, "scope_metrics": [{"scope": {"name": "app", "version": "", "schema_url": ""}, "metrics": [{"name": "healthz_count", "description": "Number of /healthz requests", "unit": "", "data": {"data_points": [{"attributes": {}, "start_time_unix_nano": 1665632818794016000, "time_unix_nano": 1665632825058633000, "value": 2}], "aggregation_temporality": 2, "is_monotonic": true}}], "schema_url": ""}], "schema_url": ""}]}
    


    추적 및 메트릭을 성공적으로 생성했습니다(때로는 표시하는 데 몇 초가 걸림).

    좋은 웹페이지 즐겨찾기