v0.0.32 | LogoutView 추가 및 OpenTelemetry 확장
All checks were successful
Build And Test / build-and-push (push) Successful in 2m21s

- LogoutView 추가: refresh token 블랙리스트 처리
- OpenTelemetry instrumentation 확장: requests, logging, dbapi
- TRACE_CA_CERT TLS 지원 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-23 02:40:27 +09:00
parent ca43c73dfb
commit 86064d48f9
5 changed files with 1194 additions and 807 deletions

View File

@ -17,12 +17,17 @@ from django.core.wsgi import get_wsgi_application
# ✅ DEBUG 모드 아닐 때만 OpenTelemetry 활성 # ✅ DEBUG 모드 아닐 때만 OpenTelemetry 활성
if not settings.DEBUG: if not settings.DEBUG:
import grpc
from opentelemetry import trace from opentelemetry import trace
from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.django import DjangoInstrumentor from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
from opentelemetry.instrumentation.logging import LoggingInstrumentor
from opentelemetry.instrumentation.dbapi import trace_integration
import MySQLdb
trace.set_tracer_provider( trace.set_tracer_provider(
TracerProvider( TracerProvider(
@ -34,11 +39,25 @@ if not settings.DEBUG:
) )
) )
# TRACE_CA_CERT 설정에 따른 gRPC credentials 구성
# - 값이 있고 파일 존재: TLS + 해당 CA 인증서 사용
# - 값이 없거나 파일 없음: insecure 모드 (TLS 없이 연결)
credentials = None
ca_cert_path = os.getenv('TRACE_CA_CERT', '').strip()
if ca_cert_path and os.path.exists(ca_cert_path):
with open(ca_cert_path, 'rb') as f:
ca_cert = f.read()
credentials = grpc.ssl_channel_credentials(root_certificates=ca_cert)
insecure = False
else:
insecure = True
otlp_exporter = OTLPSpanExporter( otlp_exporter = OTLPSpanExporter(
# endpoint="http://jaeger-collector.istio-system:4317", # endpoint="http://jaeger-collector.istio-system:4317",
# endpoint="jaeger-collector.observability.svc.cluster.local:4317", # endpoint="jaeger-collector.observability.svc.cluster.local:4317",
endpoint=settings.TRACE_ENDPOINT, endpoint=settings.TRACE_ENDPOINT,
insecure=True, insecure=insecure,
credentials=credentials,
headers={ headers={
"x-scope-orgid": settings.SERVICE_PLATFORM, "x-scope-orgid": settings.SERVICE_PLATFORM,
"x-service": settings.TRACE_SERVICE_NAME "x-service": settings.TRACE_SERVICE_NAME
@ -49,8 +68,23 @@ if not settings.DEBUG:
BatchSpanProcessor(otlp_exporter) BatchSpanProcessor(otlp_exporter)
) )
# Django 요청/응답 추적
DjangoInstrumentor().instrument() DjangoInstrumentor().instrument()
# HTTP 클라이언트 요청 추적 (requests 라이브러리)
RequestsInstrumentor().instrument()
# 로그와 Trace 연동 (trace_id, span_id를 로그에 자동 추가)
LoggingInstrumentor().instrument(set_logging_format=True)
# MySQL DB 쿼리 추적
trace_integration(
MySQLdb,
"connect",
"mysql",
capture_parameters=True, # 쿼리 파라미터 캡처
)
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application

View File

@ -26,7 +26,10 @@ opentelemetry-exporter-otlp-proto-common==1.34.0
opentelemetry-exporter-otlp-proto-grpc==1.34.0 opentelemetry-exporter-otlp-proto-grpc==1.34.0
opentelemetry-exporter-otlp-proto-http==1.34.0 opentelemetry-exporter-otlp-proto-http==1.34.0
opentelemetry-instrumentation==0.55b0 opentelemetry-instrumentation==0.55b0
opentelemetry-instrumentation-dbapi==0.55b0
opentelemetry-instrumentation-django==0.55b0 opentelemetry-instrumentation-django==0.55b0
opentelemetry-instrumentation-logging==0.55b0
opentelemetry-instrumentation-requests==0.55b0
opentelemetry-instrumentation-wsgi==0.55b0 opentelemetry-instrumentation-wsgi==0.55b0
opentelemetry-proto==1.34.0 opentelemetry-proto==1.34.0
opentelemetry-sdk==1.34.0 opentelemetry-sdk==1.34.0

View File

@ -1,6 +1,6 @@
from django.urls import path from django.urls import path
from .views import ( from .views import (
RegisterView, MeView, ChangePasswordView, ExtendPasswordExpiryView, CustomTokenObtainPairView, RegisterView, LogoutView, MeView, ChangePasswordView, ExtendPasswordExpiryView, CustomTokenObtainPairView,
SSHKeyUploadView, SSHKeyInfoView, SSHKeyRetrieveView, SSHKeyUploadView, SSHKeyInfoView, SSHKeyRetrieveView,
UserListView, UserUpdateView, UserListView, UserUpdateView,
NHNCloudCredentialsView, NHNCloudPasswordView, NHNCloudCredentialsView, NHNCloudPasswordView,
@ -22,6 +22,7 @@ urlpatterns = [
path('register/', RegisterView.as_view(), name='register'), path('register/', RegisterView.as_view(), name='register'),
# path('login/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # path('login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('login/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'), path('login/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('logout/', LogoutView.as_view(), name='logout'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('verify/', TokenVerifyView.as_view(), name='token_verify'), path('verify/', TokenVerifyView.as_view(), name='token_verify'),
path('me/', MeView.as_view(), name='me'), path('me/', MeView.as_view(), name='me'),

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
v0.0.31 v0.0.32