Honor OTEL_SERVICE_NAME and set service name/version for all processes
This commit is contained in:
parent
da0748916b
commit
da79f92af1
6 changed files with 87 additions and 13 deletions
|
|
@ -1,6 +1,10 @@
|
|||
# Changelog
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Logfire spans carry `service.version` and a per-process `service.name` (`haiku-ingester`, `haiku-rag`, `haiku-rag-app`); `OTEL_SERVICE_NAME` / `LOGFIRE_SERVICE_NAME` override the default.
|
||||
|
||||
## [0.65.0] - 2026-07-09
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ from haiku.rag.client import HaikuRAG
|
|||
from haiku.rag.config import load_yaml_config
|
||||
from haiku.rag.config.models import AppConfig
|
||||
from haiku.rag.skills.rag import create_skill, get_agent_preamble
|
||||
from haiku.rag.telemetry import configure as configure_telemetry
|
||||
from haiku.rag.utils import get_model
|
||||
from haiku.skills import (
|
||||
SkillDeps,
|
||||
|
|
@ -30,14 +31,7 @@ from haiku.skills.prompts import build_system_prompt
|
|||
|
||||
load_dotenv(find_dotenv(usecwd=True))
|
||||
|
||||
# Configure logfire (only sends data if LOGFIRE_TOKEN is present)
|
||||
try:
|
||||
import logfire
|
||||
|
||||
logfire.configure(send_to_logfire="if-token-present", console=False)
|
||||
logfire.instrument_pydantic_ai()
|
||||
except Exception:
|
||||
pass
|
||||
configure_telemetry(service_name="haiku-rag-app")
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ from haiku.skills.agent import (
|
|||
from haiku.skills.models import Skill
|
||||
from haiku.skills.prompts import build_system_prompt
|
||||
|
||||
configure_telemetry()
|
||||
configure_telemetry(service_name="haiku-rag")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from textual.app import ComposeResult
|
||||
|
|
|
|||
|
|
@ -137,7 +137,9 @@ def main(
|
|||
from haiku.rag.telemetry import configure as configure_telemetry
|
||||
|
||||
is_production = get_config().environment != "development"
|
||||
configure_telemetry(console=False if is_production else None)
|
||||
configure_telemetry(
|
||||
service_name="haiku-rag", console=False if is_production else None
|
||||
)
|
||||
|
||||
if get_config().environment != "development":
|
||||
# Suppress warnings in production
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import os
|
||||
from importlib import metadata
|
||||
from typing import Literal
|
||||
|
||||
from logfire import Logfire, attach_context, get_context
|
||||
|
|
@ -25,8 +27,10 @@ def configure(
|
|||
Silently no-ops on failure so a missing/misconfigured LOGFIRE_TOKEN
|
||||
never crashes the app.
|
||||
|
||||
- service_name: identifies the process in the Logfire UI (e.g.
|
||||
"haiku-ingester"). Falls back to logfire's default when None.
|
||||
- service_name: the default name for this process in the Logfire UI
|
||||
(e.g. "haiku-ingester"). The OTEL_SERVICE_NAME / LOGFIRE_SERVICE_NAME
|
||||
env vars, when set, take precedence so operators can distinguish
|
||||
concurrent processes.
|
||||
- console: False (default) suppresses span lines on stderr so they
|
||||
don't interleave with RichHandler logs. Pass None to let logfire
|
||||
decide (its own default applies).
|
||||
|
|
@ -34,8 +38,21 @@ def configure(
|
|||
try:
|
||||
import logfire as _lf
|
||||
|
||||
# An explicit service_name arg would beat the env vars in logfire's
|
||||
# precedence; deferring to None when an env var is set lets the
|
||||
# operator's OTEL_SERVICE_NAME / LOGFIRE_SERVICE_NAME win over our
|
||||
# per-process default.
|
||||
env_service = os.environ.get("OTEL_SERVICE_NAME") or os.environ.get(
|
||||
"LOGFIRE_SERVICE_NAME"
|
||||
)
|
||||
try:
|
||||
service_version = metadata.version("haiku.rag-slim")
|
||||
except metadata.PackageNotFoundError: # pragma: no cover
|
||||
service_version = None
|
||||
|
||||
_lf.configure(
|
||||
service_name=service_name,
|
||||
service_name=None if env_service else service_name,
|
||||
service_version=service_version,
|
||||
send_to_logfire="if-token-present",
|
||||
console=console,
|
||||
)
|
||||
|
|
|
|||
57
tests/test_telemetry.py
Normal file
57
tests/test_telemetry.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
from importlib import metadata
|
||||
|
||||
import logfire
|
||||
import pytest
|
||||
|
||||
from haiku.rag import telemetry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def captured_configure(monkeypatch):
|
||||
"""Capture the kwargs telemetry.configure() passes to logfire.configure,
|
||||
and no-op the instrumentation so tests don't touch a real exporter."""
|
||||
captured: dict = {}
|
||||
|
||||
def _fake_configure(**kwargs):
|
||||
captured.update(kwargs)
|
||||
|
||||
monkeypatch.setattr(logfire, "configure", _fake_configure)
|
||||
monkeypatch.setattr(logfire, "instrument_pydantic_ai", lambda: None)
|
||||
return captured
|
||||
|
||||
|
||||
def test_default_service_name_used_when_env_unset(captured_configure, monkeypatch):
|
||||
monkeypatch.delenv("OTEL_SERVICE_NAME", raising=False)
|
||||
monkeypatch.delenv("LOGFIRE_SERVICE_NAME", raising=False)
|
||||
|
||||
telemetry.configure(service_name="haiku-ingester")
|
||||
|
||||
assert captured_configure["service_name"] == "haiku-ingester"
|
||||
|
||||
|
||||
def test_otel_service_name_overrides_default(captured_configure, monkeypatch):
|
||||
monkeypatch.setenv("OTEL_SERVICE_NAME", "customer-ingester")
|
||||
|
||||
telemetry.configure(service_name="haiku-ingester")
|
||||
|
||||
# Deferring to logfire (service_name=None) lets it read the env var,
|
||||
# so the customer's OTEL_SERVICE_NAME wins over our default.
|
||||
assert captured_configure["service_name"] is None
|
||||
|
||||
|
||||
def test_logfire_service_name_overrides_default(captured_configure, monkeypatch):
|
||||
monkeypatch.delenv("OTEL_SERVICE_NAME", raising=False)
|
||||
monkeypatch.setenv("LOGFIRE_SERVICE_NAME", "customer-ingester")
|
||||
|
||||
telemetry.configure(service_name="haiku-ingester")
|
||||
|
||||
assert captured_configure["service_name"] is None
|
||||
|
||||
|
||||
def test_service_version_is_package_version(captured_configure, monkeypatch):
|
||||
monkeypatch.delenv("OTEL_SERVICE_NAME", raising=False)
|
||||
monkeypatch.delenv("LOGFIRE_SERVICE_NAME", raising=False)
|
||||
|
||||
telemetry.configure(service_name="haiku-rag")
|
||||
|
||||
assert captured_configure["service_version"] == metadata.version("haiku.rag-slim")
|
||||
Loading…
Reference in a new issue