설치

Sophonz Python SDK 설치와 초기화 — init()으로 코드에서, 또는 opentelemetry-instrument 명령으로 — 그리고 gunicorn과 uvicorn에서 정상 종료하기.

프레임워크와 데이터베이스에 맞는 extra와 함께 sophonz-opentelemetry를 설치하고, 애플리케이션의 다른 모듈보다 먼저 init()을 호출하세요. 코드를 바꾸고 싶지 않다면 opentelemetry-instrument로 앱을 실행하면 됩니다.

빠른 시작

아래에서 수집기 URL, 프로젝트, 앱 이름, 버전, 앱 키를 입력하고 탭(Plain Python · Flask · FastAPI)을 선택하면 그 값으로 초기화 코드가 생성됩니다. 고급 옵션은 "고급 옵션" 토글 뒤에 있습니다.

# instrument.py — 앱의 나머지 코드보다 먼저 import 하세요
from sophonz.opentelemetry import init

init(
    service="next-sample",
    service_version="1.0.0",
    service_namespace="sophonz",
    api_key="sk_tYtJUa4WweXXedj6lxjSqoPW5O0DnbXz",
    endpoint="https://in.sophonz.ai",
)

설치

pip install "sophonz-opentelemetry[flask,psycopg]"
# 또는
uv add "sophonz-opentelemetry[fastapi,psycopg]"
# 또는
poetry add "sophonz-opentelemetry[django,psycopg]"

각 extra는 해당 OpenTelemetry 계측을 설치합니다.

Extra설치되는 패키지
flaskopentelemetry-instrumentation-flask
fastapiopentelemetry-instrumentation-fastapi
djangoopentelemetry-instrumentation-django
psycopgopentelemetry-instrumentation-psycopg (psycopg 3)
psycopg2opentelemetry-instrumentation-psycopg2
sqlalchemyopentelemetry-instrumentation-sqlalchemy
requestsopentelemetry-instrumentation-requests
httpxopentelemetry-instrumentation-httpx
loggingopentelemetry-instrumentation-logging
grpcopentelemetry-exporter-otlp-proto-grpc (OTEL_EXPORTER_OTLP_PROTOCOL=grpc용)

현재 환경에서 감지된 모든 라이브러리의 계측을 한 번에 설치하려면 다음을 실행합니다.

opentelemetry-bootstrap -a install

TIP — API 키 발급

Sophonz 콘솔에 로그인해 앱을 등록하고 발급된 키(sk_...)를 복사하세요. api_key 인자 또는 SOPHONZ_API_KEY 환경 변수로 전달합니다. API 키가 없고 OTEL_EXPORTER_OTLP_HEADERS도 없으면 SDK는 경고를 남기고 초기화를 건너뜁니다.

프로그래밍 방식 초기화

Flask, FastAPI, Django, 데이터베이스 클라이언트를 import하기 전에, 가능한 한 먼저 init()을 호출하세요. 프레임워크별 정확한 위치는 프레임워크 가이드에 있습니다.

# instrument.py
import os
 
from sophonz.opentelemetry import init
 
init(
    service="my-app",
    api_key=os.getenv("SOPHONZ_API_KEY"),
)
# app.py
import instrument  # noqa: F401  (반드시 가장 먼저)
 
from flask import Flask
 
app = Flask(__name__)

init()은 설치된 모든 OpenTelemetry 계측을 로드하고 Sophonz 권장 기본값인 콘솔(logging) 캡처와 예외 캡처를 켭니다. 모든 옵션을 직접 제어하려면 init_sdk()를 사용하세요 — 설정을 참고하세요.

init()은 SDK가 시작되면 True를, 키가 없어 건너뛰었거나 이미 실행 중이면 False를 반환합니다. OpenTelemetry는 전역 프로바이더를 한 번만 설정할 수 있으므로 프로세스당 한 번만 호출하세요.

NOTE — Django

Django 계측은 로드될 때 설정을 읽으므로, manage.py, wsgi.py, asgi.py에서 init()을 호출하기 전에 DJANGO_SETTINGS_MODULE을 설정하세요. 예제를 참고하세요.

opentelemetry-instrument (코드 변경 없음)

환경 변수로 SDK를 설정하고 실행 명령 앞에 붙이세요.

export SOPHONZ_API_KEY=sk_...
export OTEL_SERVICE_NAME=my-service
 
opentelemetry-instrument python app.py
opentelemetry-instrument flask run
opentelemetry-instrument uvicorn main:app
opentelemetry-instrument gunicorn app:app

opentelemetry-instrument는 패키지 엔트리 포인트로 Sophonz 배포판을 찾아 SDK를 시작한 다음, SOPHONZ_PYTHON_INSTRUMENTATIONS와 SOPHONZ_PYTHON_SQLCOMMENTER의 설정으로 설치된 계측을 모두 로드합니다. 같은 프로세스에서 init()을 함께 호출하지 마세요.

배포판은 init()이 아니라 init_sdk()의 기본값을 적용합니다. SOPHONZ_PYTHON_EXPERIMENTAL_EXCEPTION_CAPTURE=true를 설정하지 않으면 처리되지 않은 예외 캡처는 꺼져 있습니다.

NOTE — 다른 배포판이 설치되어 있다면

같은 환경에 opentelemetry-distro나 다른 배포판이 설치되어 있으면 OTEL_PYTHON_DISTRO=sophonz를 설정해 Sophonz 배포판이 선택되도록 하세요.

정상 종료

기본값(stop_on_termination_signals=True)에서 SDK는 SIGTERM과 SIGINT 핸들러를 설치합니다. 이 핸들러는 버퍼에 쌓인 텔레메트리를 flush한 뒤, 원래 있던 핸들러에 시그널을 넘깁니다. 서버 자체의 정상 종료는 그대로 동작하고, 핸들러가 없던 프로세스는 원래대로 종료됩니다. 인터프리터가 정상 종료될 때도 프로바이더가 flush됩니다.

종료를 직접 관리하려면 stop_on_termination_signals=False를 전달하고 shutdown()을 호출하세요.

import atexit
 
from sophonz.opentelemetry import init, shutdown
 
init(service="my-app", stop_on_termination_signals=False)
atexit.register(shutdown)

uvicorn

uvicorn main:app는 앱을 import하기 전에 자체 시그널 핸들러를 설치하므로, SDK 핸들러가 flush한 뒤 uvicorn의 정상 종료를 호출합니다. uvicorn은 요청 처리를 마치면 기본 핸들러를 복원하고 시그널을 다시 보내는데, 이때 프로세스는 종료 훅을 실행하지 않고 끝납니다. 그래서 sophonz_fastapi_middleware는 애플리케이션의 lifespan 종료가 끝날 때 한 번 더 flush하여, 종료 대기 중에 끝난 스팬도 내보냅니다. 이 미들웨어가 없는 ASGI 앱(예: uvicorn 위의 Django)에서는 종료 대기 중에 끝난 스팬이 마지막 전송에서 빠질 수 있으니 OTEL_BSP_SCHEDULE_DELAY를 낮추거나 종료 코드에서 force_flush()를 호출하세요. 리로더 프로세스에서 SDK가 시작되지 않도록 --reload 없이 실행하세요.

gunicorn

--preload가 없으면 각 워커는 자체 시그널 핸들러를 설치한 뒤 앱을 import하므로, SDK 핸들러가 flush한 다음 gunicorn의 핸들러를 호출하고, 워커가 정상 종료될 때 프로바이더가 다시 flush합니다. --preload를 쓰면 앱(과 init())이 워커 fork 전에 마스터에서 실행되고, gunicorn이 마스터와 각 워커에서 SDK 핸들러를 교체합니다. 그래도 워커에서 텔레메트리는 동작하며(배치 프로세서가 fork 후 전송 스레드를 다시 시작합니다) 워커가 종료될 때 flush됩니다. flush를 명시하려면 worker_exit 훅을 추가하세요.

# gunicorn.conf.py
from sophonz.opentelemetry import shutdown
 
 
def worker_exit(server, worker):
    shutdown()

--preload에서 워커마다 SDK를 따로 시작하고 싶다면 import 시점에 init()을 호출하지 말고 post_fork에서 호출하세요. gunicorn은 post_fork 이후에 워커 시그널 핸들러를 설치하므로 flush는 worker_exit에 맡기세요.

# gunicorn.conf.py
import os
 
from sophonz.opentelemetry import init, shutdown
 
preload_app = True
 
 
def post_fork(server, worker):
    init(service="my-app", api_key=os.getenv("SOPHONZ_API_KEY"))
 
 
def worker_exit(server, worker):
    shutdown()

CAUTION — macOS와 fork

macOS에서는 fork된 워커가 HTTPS로 전송할 때 Objective-C 런타임에 의해 강제 종료될 수 있습니다. macOS에서 로컬로 gunicorn을 실행할 때는 OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES를 설정하세요. Linux는 해당되지 않습니다.

다음 단계

  • 설정 — 모든 init() 옵션과 환경 변수.
  • 프레임워크 가이드 — gunicorn·uvicorn과 함께 Flask, FastAPI, Django 연결하기.
  • 배포 — 컨테이너, Kubernetes, 정상 종료.
  • 예제 — Flask, FastAPI, Django 서버 전체 예제.

TIP — 이제 시작입니다

이제 앱을 배포하세요. Sophonz가 실사용자가 겪는 문제를 포착하고, 당신의 앱은 스스로 진화합니다.