mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-10-04 12:07:34 +00:00
fix(pr specific): passes pre-commit
This commit is contained in:
parent
4aa2dc110d
commit
2b7a765d02
20 changed files with 547 additions and 516 deletions
|
@ -32,7 +32,7 @@ from termcolor import cprint
|
|||
|
||||
from llama_stack.core.build import print_pip_install_help
|
||||
from llama_stack.core.configure import parse_and_maybe_upgrade_config
|
||||
from llama_stack.core.datatypes import Api, BuildConfig, BuildProvider, DistributionSpec
|
||||
from llama_stack.core.datatypes import BuildConfig, BuildProvider, DistributionSpec
|
||||
from llama_stack.core.request_headers import (
|
||||
PROVIDER_DATA_VAR,
|
||||
request_provider_data_context,
|
||||
|
@ -49,7 +49,6 @@ from llama_stack.core.utils.context import preserve_contexts_async_generator
|
|||
from llama_stack.core.utils.exec import in_notebook
|
||||
from llama_stack.log import get_logger
|
||||
|
||||
|
||||
logger = get_logger(name=__name__, category="core")
|
||||
|
||||
T = TypeVar("T")
|
||||
|
|
|
@ -63,7 +63,6 @@ from llama_stack.core.utils.context import preserve_contexts_async_generator
|
|||
from llama_stack.log import get_logger
|
||||
from llama_stack.providers.datatypes import Api
|
||||
|
||||
|
||||
from .auth import AuthenticationMiddleware
|
||||
from .quota import QuotaMiddleware
|
||||
|
||||
|
@ -236,9 +235,7 @@ def create_dynamic_typed_route(func: Any, method: str, route: str) -> Callable:
|
|||
|
||||
try:
|
||||
if is_streaming:
|
||||
gen = preserve_contexts_async_generator(
|
||||
sse_generator(func(**kwargs)), [PROVIDER_DATA_VAR]
|
||||
)
|
||||
gen = preserve_contexts_async_generator(sse_generator(func(**kwargs)), [PROVIDER_DATA_VAR])
|
||||
return StreamingResponse(gen, media_type="text/event-stream")
|
||||
else:
|
||||
value = func(**kwargs)
|
||||
|
@ -282,7 +279,7 @@ def create_dynamic_typed_route(func: Any, method: str, route: str) -> Callable:
|
|||
]
|
||||
)
|
||||
|
||||
setattr(route_handler, "__signature__", sig.replace(parameters=new_params))
|
||||
route_handler.__signature__ = sig.replace(parameters=new_params)
|
||||
return route_handler
|
||||
|
||||
|
||||
|
|
|
@ -359,7 +359,6 @@ class Stack:
|
|||
await refresh_registry_once(impls)
|
||||
self.impls = impls
|
||||
|
||||
|
||||
# safely access impls without raising an exception
|
||||
def get_impls(self) -> dict[Api, Any]:
|
||||
if self.impls is None:
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the terms described in the LICENSE file in
|
||||
# the root directory of this source tree.
|
||||
# the root directory of this source tree.
|
||||
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the terms described in the LICENSE file in
|
||||
# the root directory of this source tree.
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
# This source code is licensed under the terms described in the LICENSE file in
|
||||
# the root directory of this source tree.
|
||||
from abc import abstractmethod
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
from opentelemetry.trace import Tracer
|
||||
from fastapi import FastAPI
|
||||
from opentelemetry.metrics import Meter
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
from opentelemetry.sdk.resources import Attributes
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.trace import Tracer
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import Engine
|
||||
|
||||
|
||||
|
@ -19,39 +19,44 @@ class TelemetryProvider(BaseModel):
|
|||
"""
|
||||
TelemetryProvider standardizes how telemetry is provided to the application.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def fastapi_middleware(self, app: FastAPI, *args, **kwargs):
|
||||
"""
|
||||
Injects FastAPI middleware that instruments the application for telemetry.
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def sqlalchemy_instrumentation(self, engine: Engine | None = None):
|
||||
"""
|
||||
Injects SQLAlchemy instrumentation that instruments the application for telemetry.
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def get_tracer(self,
|
||||
instrumenting_module_name: str,
|
||||
instrumenting_library_version: str | None = None,
|
||||
tracer_provider: TracerProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None
|
||||
def get_tracer(
|
||||
self,
|
||||
instrumenting_module_name: str,
|
||||
instrumenting_library_version: str | None = None,
|
||||
tracer_provider: TracerProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None,
|
||||
) -> Tracer:
|
||||
"""
|
||||
Gets a tracer.
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def get_meter(self, name: str,
|
||||
version: str = "",
|
||||
meter_provider: MeterProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None) -> Meter:
|
||||
def get_meter(
|
||||
self,
|
||||
name: str,
|
||||
version: str = "",
|
||||
meter_provider: MeterProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None,
|
||||
) -> Meter:
|
||||
"""
|
||||
Gets a meter.
|
||||
"""
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
from aiohttp import hdrs
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the terms described in the LICENSE file in
|
||||
# the root directory of this source tree.
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aiohttp import hdrs
|
||||
|
||||
from llama_stack.apis.datatypes import Api
|
||||
from llama_stack.core.external import ExternalApiSpec
|
||||
from llama_stack.core.server.routes import find_matching_route, initialize_route_impls
|
||||
from llama_stack.log import get_logger
|
||||
from llama_stack.providers.utils.telemetry.tracing import end_trace, start_trace
|
||||
|
||||
|
||||
logger = get_logger(name=__name__, category="telemetry::meta_reference")
|
||||
|
||||
|
||||
class TracingMiddleware:
|
||||
def __init__(
|
||||
self,
|
||||
|
|
|
@ -10,7 +10,6 @@ import threading
|
|||
from typing import Any, cast
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from opentelemetry import metrics, trace
|
||||
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
|
@ -23,11 +22,6 @@ from opentelemetry.semconv.attributes import service_attributes
|
|||
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
||||
from opentelemetry.util.types import Attributes
|
||||
|
||||
from llama_stack.core.external import ExternalApiSpec
|
||||
from llama_stack.core.server.tracing import TelemetryProvider
|
||||
from llama_stack.providers.inline.telemetry.meta_reference.middleware import TracingMiddleware
|
||||
|
||||
|
||||
from llama_stack.apis.telemetry import (
|
||||
Event,
|
||||
MetricEvent,
|
||||
|
@ -47,10 +41,13 @@ from llama_stack.apis.telemetry import (
|
|||
UnstructuredLogEvent,
|
||||
)
|
||||
from llama_stack.core.datatypes import Api
|
||||
from llama_stack.core.external import ExternalApiSpec
|
||||
from llama_stack.core.server.tracing import TelemetryProvider
|
||||
from llama_stack.log import get_logger
|
||||
from llama_stack.providers.inline.telemetry.meta_reference.console_span_processor import (
|
||||
ConsoleSpanProcessor,
|
||||
)
|
||||
from llama_stack.providers.inline.telemetry.meta_reference.middleware import TracingMiddleware
|
||||
from llama_stack.providers.inline.telemetry.meta_reference.sqlite_span_processor import (
|
||||
SQLiteSpanProcessor,
|
||||
)
|
||||
|
@ -381,7 +378,7 @@ class TelemetryAdapter(TelemetryDatasetMixin, Telemetry, TelemetryProvider):
|
|||
max_depth=max_depth,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def fastapi_middleware(
|
||||
self,
|
||||
app: FastAPI,
|
||||
|
|
|
@ -12,13 +12,12 @@ __all__ = ["OTelTelemetryConfig"]
|
|||
async def get_provider_impl(config: OTelTelemetryConfig, deps):
|
||||
"""
|
||||
Get the OTel telemetry provider implementation.
|
||||
|
||||
|
||||
This function is called by the Llama Stack registry to instantiate
|
||||
the provider.
|
||||
"""
|
||||
from .otel import OTelTelemetryProvider
|
||||
|
||||
|
||||
# The provider is synchronously initialized via Pydantic model_post_init
|
||||
# No async initialization needed
|
||||
return OTelTelemetryProvider(config=config)
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the terms described in the LICENSE file in
|
||||
# the root directory of this source tree.
|
||||
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
type BatchSpanProcessor = Literal["batch"]
|
||||
type SimpleSpanProcessor = Literal["simple"]
|
||||
|
||||
|
@ -13,26 +18,27 @@ class OTelTelemetryConfig(BaseModel):
|
|||
Most configuration is set using environment variables.
|
||||
See https://opentelemetry.io/docs/specs/otel/configuration/sdk-configuration-variables/ for more information.
|
||||
"""
|
||||
|
||||
service_name: str = Field(
|
||||
description="""The name of the service to be monitored.
|
||||
description="""The name of the service to be monitored.
|
||||
Is overridden by the OTEL_SERVICE_NAME or OTEL_RESOURCE_ATTRIBUTES environment variables.""",
|
||||
)
|
||||
service_version: str | None = Field(
|
||||
default=None,
|
||||
description="""The version of the service to be monitored.
|
||||
Is overriden by the OTEL_RESOURCE_ATTRIBUTES environment variable."""
|
||||
description="""The version of the service to be monitored.
|
||||
Is overriden by the OTEL_RESOURCE_ATTRIBUTES environment variable.""",
|
||||
)
|
||||
deployment_environment: str | None = Field(
|
||||
default=None,
|
||||
description="""The name of the environment of the service to be monitored.
|
||||
Is overriden by the OTEL_RESOURCE_ATTRIBUTES environment variable."""
|
||||
description="""The name of the environment of the service to be monitored.
|
||||
Is overriden by the OTEL_RESOURCE_ATTRIBUTES environment variable.""",
|
||||
)
|
||||
span_processor: BatchSpanProcessor | SimpleSpanProcessor | None = Field(
|
||||
description="""The span processor to use.
|
||||
description="""The span processor to use.
|
||||
Is overriden by the OTEL_SPAN_PROCESSOR environment variable.""",
|
||||
default="batch"
|
||||
default="batch",
|
||||
)
|
||||
|
||||
|
||||
@classmethod
|
||||
def sample_run_config(cls, __distro_dir__: str = "") -> dict[str, Any]:
|
||||
"""Sample configuration for use in distributions."""
|
||||
|
|
|
@ -1,24 +1,28 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the terms described in the LICENSE file in
|
||||
# the root directory of this source tree.
|
||||
|
||||
import os
|
||||
|
||||
from opentelemetry import trace, metrics
|
||||
from fastapi import FastAPI
|
||||
from opentelemetry import metrics, trace
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
||||
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
||||
from opentelemetry.metrics import Meter
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
from opentelemetry.sdk.resources import Attributes, Resource
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SimpleSpanProcessor
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
||||
from opentelemetry.trace import Tracer
|
||||
from opentelemetry.metrics import Meter
|
||||
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
||||
from sqlalchemy import Engine
|
||||
|
||||
from llama_stack.core.telemetry.telemetry import TelemetryProvider
|
||||
from llama_stack.log import get_logger
|
||||
|
||||
from sqlalchemy import Engine
|
||||
|
||||
from .config import OTelTelemetryConfig
|
||||
from fastapi import FastAPI
|
||||
|
||||
|
||||
logger = get_logger(name=__name__, category="telemetry::otel")
|
||||
|
||||
|
@ -27,6 +31,7 @@ class OTelTelemetryProvider(TelemetryProvider):
|
|||
"""
|
||||
A simple Open Telemetry native telemetry provider.
|
||||
"""
|
||||
|
||||
config: OTelTelemetryConfig
|
||||
|
||||
def model_post_init(self, __context):
|
||||
|
@ -56,66 +61,66 @@ class OTelTelemetryProvider(TelemetryProvider):
|
|||
tracer_provider.add_span_processor(BatchSpanProcessor(otlp_span_exporter))
|
||||
elif self.config.span_processor == "simple":
|
||||
tracer_provider.add_span_processor(SimpleSpanProcessor(otlp_span_exporter))
|
||||
|
||||
|
||||
meter_provider = MeterProvider(resource=resource)
|
||||
metrics.set_meter_provider(meter_provider)
|
||||
|
||||
# Do not fail the application, but warn the user if the endpoints are not set properly.
|
||||
if not os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT"):
|
||||
if not os.environ.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"):
|
||||
logger.warning("OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is not set. Traces will not be exported.")
|
||||
logger.warning(
|
||||
"OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_TRACES_ENDPOINT is not set. Traces will not be exported."
|
||||
)
|
||||
if not os.environ.get("OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"):
|
||||
logger.warning("OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT is not set. Metrics will not be exported.")
|
||||
|
||||
logger.warning(
|
||||
"OTEL_EXPORTER_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_METRICS_ENDPOINT is not set. Metrics will not be exported."
|
||||
)
|
||||
|
||||
def fastapi_middleware(self, app: FastAPI):
|
||||
"""
|
||||
Instrument FastAPI with OTel for automatic tracing and metrics.
|
||||
|
||||
|
||||
Captures:
|
||||
- Distributed traces for all HTTP requests (via FastAPIInstrumentor)
|
||||
- HTTP metrics following semantic conventions (custom middleware)
|
||||
"""
|
||||
# Enable automatic tracing
|
||||
FastAPIInstrumentor.instrument_app(app)
|
||||
|
||||
|
||||
# Add custom middleware for HTTP metrics
|
||||
meter = self.get_meter("llama_stack.http.server")
|
||||
|
||||
|
||||
# Create HTTP metrics following semantic conventions
|
||||
# https://opentelemetry.io/docs/specs/semconv/http/http-metrics/
|
||||
request_duration = meter.create_histogram(
|
||||
"http.server.request.duration",
|
||||
unit="ms",
|
||||
description="Duration of HTTP server requests"
|
||||
"http.server.request.duration", unit="ms", description="Duration of HTTP server requests"
|
||||
)
|
||||
|
||||
|
||||
active_requests = meter.create_up_down_counter(
|
||||
"http.server.active_requests",
|
||||
unit="requests",
|
||||
description="Number of active HTTP server requests"
|
||||
"http.server.active_requests", unit="requests", description="Number of active HTTP server requests"
|
||||
)
|
||||
|
||||
|
||||
request_count = meter.create_counter(
|
||||
"http.server.request.count",
|
||||
unit="requests",
|
||||
description="Total number of HTTP server requests"
|
||||
"http.server.request.count", unit="requests", description="Total number of HTTP server requests"
|
||||
)
|
||||
|
||||
|
||||
# Add middleware to record metrics
|
||||
@app.middleware("http") # type: ignore[misc]
|
||||
async def http_metrics_middleware(request, call_next):
|
||||
import time
|
||||
|
||||
|
||||
# Record active request
|
||||
active_requests.add(1, {
|
||||
"http.method": request.method,
|
||||
"http.route": request.url.path,
|
||||
})
|
||||
|
||||
active_requests.add(
|
||||
1,
|
||||
{
|
||||
"http.method": request.method,
|
||||
"http.route": request.url.path,
|
||||
},
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
status_code = 500 # Default to error
|
||||
|
||||
|
||||
try:
|
||||
response = await call_next(request)
|
||||
status_code = response.status_code
|
||||
|
@ -124,22 +129,24 @@ class OTelTelemetryProvider(TelemetryProvider):
|
|||
finally:
|
||||
# Record metrics
|
||||
duration_ms = (time.time() - start_time) * 1000
|
||||
|
||||
|
||||
attributes = {
|
||||
"http.method": request.method,
|
||||
"http.route": request.url.path,
|
||||
"http.status_code": status_code,
|
||||
}
|
||||
|
||||
|
||||
request_duration.record(duration_ms, attributes)
|
||||
request_count.add(1, attributes)
|
||||
active_requests.add(-1, {
|
||||
"http.method": request.method,
|
||||
"http.route": request.url.path,
|
||||
})
|
||||
|
||||
return response
|
||||
active_requests.add(
|
||||
-1,
|
||||
{
|
||||
"http.method": request.method,
|
||||
"http.route": request.url.path,
|
||||
},
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def sqlalchemy_instrumentation(self, engine: Engine | None = None):
|
||||
kwargs = {}
|
||||
|
@ -147,34 +154,30 @@ class OTelTelemetryProvider(TelemetryProvider):
|
|||
kwargs["engine"] = engine
|
||||
SQLAlchemyInstrumentor().instrument(**kwargs)
|
||||
|
||||
|
||||
def get_tracer(self,
|
||||
instrumenting_module_name: str,
|
||||
instrumenting_library_version: str | None = None,
|
||||
tracer_provider: TracerProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None
|
||||
def get_tracer(
|
||||
self,
|
||||
instrumenting_module_name: str,
|
||||
instrumenting_library_version: str | None = None,
|
||||
tracer_provider: TracerProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None,
|
||||
) -> Tracer:
|
||||
return trace.get_tracer(
|
||||
instrumenting_module_name=instrumenting_module_name,
|
||||
instrumenting_library_version=instrumenting_library_version,
|
||||
tracer_provider=tracer_provider,
|
||||
schema_url=schema_url,
|
||||
attributes=attributes
|
||||
instrumenting_module_name=instrumenting_module_name,
|
||||
instrumenting_library_version=instrumenting_library_version,
|
||||
tracer_provider=tracer_provider,
|
||||
schema_url=schema_url,
|
||||
attributes=attributes,
|
||||
)
|
||||
|
||||
|
||||
def get_meter(self,
|
||||
name: str,
|
||||
version: str = "",
|
||||
meter_provider: MeterProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None
|
||||
def get_meter(
|
||||
self,
|
||||
name: str,
|
||||
version: str = "",
|
||||
meter_provider: MeterProvider | None = None,
|
||||
schema_url: str | None = None,
|
||||
attributes: Attributes | None = None,
|
||||
) -> Meter:
|
||||
return metrics.get_meter(
|
||||
name=name,
|
||||
version=version,
|
||||
meter_provider=meter_provider,
|
||||
schema_url=schema_url,
|
||||
attributes=attributes
|
||||
)
|
||||
name=name, version=version, meter_provider=meter_provider, schema_url=schema_url, attributes=attributes
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue