浏览代码

added otel logging handler

expruc 2 月之前
父节点
当前提交
2035eabb1f
共有 3 个文件被更改,包括 59 次插入3 次删除
  1. 1 0
      backend/open_webui/env.py
  2. 5 3
      backend/open_webui/utils/logger.py
  3. 53 0
      backend/open_webui/utils/telemetry/logs.py

+ 1 - 0
backend/open_webui/env.py

@@ -643,6 +643,7 @@ AUDIT_EXCLUDED_PATHS = [path.lstrip("/") for path in AUDIT_EXCLUDED_PATHS]
 
 ENABLE_OTEL = os.environ.get("ENABLE_OTEL", "False").lower() == "true"
 ENABLE_OTEL_METRICS = os.environ.get("ENABLE_OTEL_METRICS", "False").lower() == "true"
+ENABLE_OTEL_LOGS = os.environ.get("ENABLE_OTEL_LOGS", "False").lower() == "true"
 OTEL_EXPORTER_OTLP_ENDPOINT = os.environ.get(
     "OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"
 )

+ 5 - 3
backend/open_webui/utils/logger.py

@@ -5,8 +5,6 @@ from typing import TYPE_CHECKING
 
 from loguru import logger
 from opentelemetry import trace
-
-
 from open_webui.env import (
     AUDIT_UVICORN_LOGGER_NAMES,
     AUDIT_LOG_FILE_ROTATION_SIZE,
@@ -14,6 +12,7 @@ from open_webui.env import (
     AUDIT_LOGS_FILE_PATH,
     GLOBAL_LOG_LEVEL,
     ENABLE_OTEL,
+    ENABLE_OTEL_LOGS,
 )
 
 
@@ -65,6 +64,10 @@ class InterceptHandler(logging.Handler):
         logger.opt(depth=depth, exception=record.exc_info).bind(
             **self._get_extras()
         ).log(level, record.getMessage())
+        if ENABLE_OTEL and ENABLE_OTEL_LOGS:
+            from open_webui.utils.telemetry.logs import otel_handler
+
+            otel_handler.emit(record)
 
     def _get_extras(self):
         if not ENABLE_OTEL:
@@ -126,7 +129,6 @@ def start_logger():
         format=stdout_format,
         filter=lambda record: "auditable" not in record["extra"],
     )
-
     if AUDIT_LOG_LEVEL != "NONE":
         try:
             logger.add(

+ 53 - 0
backend/open_webui/utils/telemetry/logs.py

@@ -0,0 +1,53 @@
+import logging
+from base64 import b64encode
+from opentelemetry.sdk._logs import (
+    LoggingHandler,
+    LoggerProvider,
+)
+from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter
+from opentelemetry.exporter.otlp.proto.http._log_exporter import (
+    OTLPLogExporter as HttpOTLPLogExporter,
+)
+from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
+from opentelemetry._logs import set_logger_provider
+from opentelemetry.sdk.resources import SERVICE_NAME, Resource
+from open_webui.env import (
+    OTEL_SERVICE_NAME,
+    OTEL_EXPORTER_OTLP_ENDPOINT,
+    OTEL_EXPORTER_OTLP_INSECURE,
+    OTEL_BASIC_AUTH_USERNAME,
+    OTEL_BASIC_AUTH_PASSWORD,
+    OTEL_OTLP_SPAN_EXPORTER,
+)
+
+
+def setup_logging():
+    headers = []
+    if OTEL_BASIC_AUTH_USERNAME and OTEL_BASIC_AUTH_PASSWORD:
+        auth_string = f"{OTEL_BASIC_AUTH_USERNAME}:{OTEL_BASIC_AUTH_PASSWORD}"
+        auth_header = b64encode(auth_string.encode()).decode()
+        headers = [("authorization", f"Basic {auth_header}")]
+    resource = Resource.create(attributes={SERVICE_NAME: OTEL_SERVICE_NAME})
+
+    if OTEL_OTLP_SPAN_EXPORTER == "http":
+        exporter = HttpOTLPLogExporter(
+            endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
+            headers=headers,
+        )
+    else:
+        exporter = OTLPLogExporter(
+            endpoint=OTEL_EXPORTER_OTLP_ENDPOINT,
+            insecure=OTEL_EXPORTER_OTLP_INSECURE,
+            headers=headers,
+        )
+    logger_provider = LoggerProvider(resource=resource)
+    set_logger_provider(logger_provider)
+
+    logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
+
+    otel_handler = LoggingHandler(logger_provider=logger_provider)
+
+    return otel_handler
+
+
+otel_handler = setup_logging()