This commit is contained in:
Florian Verdonck 2025-05-29 17:00:42 -07:00 committed by GitHub
commit 7bc8a27565
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 64 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import time
import datetime import datetime
import logging import logging
from aiohttp import ClientSession from aiohttp import ClientSession
from open_webui.utils.telemetry import setup
from open_webui.models.auths import ( from open_webui.models.auths import (
AddUserForm, AddUserForm,
@ -32,6 +33,7 @@ from open_webui.env import (
WEBUI_AUTH_SIGNOUT_REDIRECT_URL, WEBUI_AUTH_SIGNOUT_REDIRECT_URL,
SRC_LOG_LEVELS, SRC_LOG_LEVELS,
) )
from open_webui.utils.telemetry import metrics
from fastapi import APIRouter, Depends, HTTPException, Request, status from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import RedirectResponse, Response, JSONResponse from fastapi.responses import RedirectResponse, Response, JSONResponse
from open_webui.config import OPENID_PROVIDER_URL, ENABLE_OAUTH_SIGNUP, ENABLE_LDAP from open_webui.config import OPENID_PROVIDER_URL, ENABLE_OAUTH_SIGNUP, ENABLE_LDAP
@ -304,6 +306,9 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
user = Auths.authenticate_user_by_email(email) user = Auths.authenticate_user_by_email(email)
if user: if user:
if metrics.telemetry_metrics is not None:
metrics.telemetry_metrics.track_user_login(user.id, user.email)
expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN) expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN)
expires_at = None expires_at = None
if expires_delta: if expires_delta:
@ -409,6 +414,8 @@ async def signin(request: Request, response: Response, form_data: SigninForm):
user = Auths.authenticate_user(form_data.email.lower(), form_data.password) user = Auths.authenticate_user(form_data.email.lower(), form_data.password)
if user: if user:
if metrics.telemetry_metrics is not None:
metrics.telemetry_metrics.track_user_login(user.id, user.email)
expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN) expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN)
expires_at = None expires_at = None

View File

@ -23,6 +23,7 @@ from pydantic import BaseModel
from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.auth import get_admin_user, get_verified_user
from open_webui.utils.access_control import has_permission from open_webui.utils.access_control import has_permission
from open_webui.utils.telemetry import metrics
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"]) log.setLevel(SRC_LOG_LEVELS["MODELS"])
@ -116,6 +117,8 @@ async def get_user_chat_list_by_user_id(
async def create_new_chat(form_data: ChatForm, user=Depends(get_verified_user)): async def create_new_chat(form_data: ChatForm, user=Depends(get_verified_user)):
try: try:
chat = Chats.insert_new_chat(user.id, form_data) chat = Chats.insert_new_chat(user.id, form_data)
if metrics.telemetry_metrics is not None:
metrics.telemetry_metrics.track_user_request(user.id)
return ChatResponse(**chat.model_dump()) return ChatResponse(**chat.model_dump())
except Exception as e: except Exception as e:
log.exception(e) log.exception(e)

View File

@ -0,0 +1,27 @@
from typing import Optional
class TelemetryMetrics:
def __init__(self, meter):
self.login_counter = meter.create_counter(
"user_login_total", description="Total number of user logins"
)
self.user_request_counter = meter.create_counter(
"user_request_total", description="Total number of user requests"
)
def track_user_login(self, user_id: str, email: str):
self.login_counter.add(
1, {"method": "regular", "user_id": user_id, "email": email}
)
def track_user_request(self, user_id: str):
self.user_request_counter.add(1, {"user_id": user_id})
telemetry_metrics: Optional[TelemetryMetrics] = None
def initialize_telemetry_metrics(meter):
global telemetry_metrics
telemetry_metrics = TelemetryMetrics(meter)

View File

@ -1,8 +1,14 @@
from fastapi import FastAPI from fastapi import FastAPI
from opentelemetry import trace from open_webui.utils.telemetry.metrics import initialize_telemetry_metrics
from opentelemetry import trace, metrics
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
PeriodicExportingMetricReader,
)
from sqlalchemy import Engine from sqlalchemy import Engine
from open_webui.utils.telemetry.exporters import LazyBatchSpanProcessor from open_webui.utils.telemetry.exporters import LazyBatchSpanProcessor
@ -11,13 +17,26 @@ from open_webui.env import OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT
def setup(app: FastAPI, db_engine: Engine): def setup(app: FastAPI, db_engine: Engine):
resource = Resource.create(attributes={SERVICE_NAME: OTEL_SERVICE_NAME})
# set up trace # set up trace
trace.set_tracer_provider( trace_provider = TracerProvider(resource=resource)
TracerProvider( trace.set_tracer_provider(trace_provider)
resource=Resource.create(attributes={SERVICE_NAME: OTEL_SERVICE_NAME})
)
)
# otlp export # otlp export
exporter = OTLPSpanExporter(endpoint=OTEL_EXPORTER_OTLP_ENDPOINT) span_exporter = OTLPSpanExporter(
trace.get_tracer_provider().add_span_processor(LazyBatchSpanProcessor(exporter)) endpoint=OTEL_EXPORTER_OTLP_ENDPOINT, insecure=True
)
trace_provider.add_span_processor(LazyBatchSpanProcessor(span_exporter))
Instrumentor(app=app, db_engine=db_engine).instrument() Instrumentor(app=app, db_engine=db_engine).instrument()
# set up metrics
metric_exporter = OTLPMetricExporter(
endpoint=OTEL_EXPORTER_OTLP_ENDPOINT, insecure=True
)
reader = PeriodicExportingMetricReader(
exporter=metric_exporter, export_interval_millis=5000
)
meter_provider = MeterProvider(resource=resource, metric_readers=[reader])
metrics.set_meter_provider(meter_provider)
meter = metrics.get_meter(OTEL_SERVICE_NAME)
initialize_telemetry_metrics(meter)