A standardized, file-based telemetry toolkit for LLM Agents.
Project description
LLM Telemetry Toolkit
Use Case Synopsis
llm-telemetry-toolkit is a production-focused telemetry layer for LLM agents and tools.
It captures structured interactions with async queue writes (or true sync writes when needed), sanitizes content, and emits JSON/Markdown/CSV logs for local debugging, analytics, and release-grade observability.
Installation
pip install llm-telemetry-toolkit
Optional OpenTelemetry export support:
pip install "llm-telemetry-toolkit[otel]"
Integration Guide
1) Standalone usage
from llm_telemetry_toolkit import LLMInteraction, LLMLogger, TelemetryConfig
config = TelemetryConfig(
session_id="demo_session",
output_formats=["json", "md", "csv"],
ensure_ascii=False,
)
logger = LLMLogger(config)
result = logger.log(
LLMInteraction(
session_id="demo_session",
model_name="my-model",
prompt="Explain Rayleigh scattering in one sentence.",
response="The sky looks blue because shorter blue wavelengths scatter more in the atmosphere.",
response_time_seconds=0.52,
),
sync=True,
)
print(result.model_dump())
logger.shutdown()
2) Agentic / MCP usage
Use this package as your telemetry boundary around tool execution:
from llm_telemetry_toolkit import LLMInteraction, LLMLogger, SessionContext, TelemetryConfig
logger = LLMLogger(TelemetryConfig(session_id="agent_run_001", mask_pii=True))
def run_tool(tool_name: str, tool_input: str, tool_output: str, latency: float) -> None:
logger.log(
LLMInteraction(
session_id="agent_run_001",
model_name="deepseek:r1",
interaction_type="tool_call",
tool_name=tool_name,
prompt=tool_input,
response=tool_output,
response_time_seconds=latency,
metadata={"trace_layer": "mcp_server"},
)
)
with SessionContext("user_session_abc"):
run_tool("web_scraper", "https://example.com", "200 OK", 0.23)
logger.shutdown()
3) Ollama adapters (sync + async, package-native)
import asyncio
from llm_telemetry_toolkit import AsyncOllamaClient, OllamaClient, OllamaTransportConfig
transport = OllamaTransportConfig(max_retries=2, backoff_initial_seconds=0.2)
sync_client = OllamaClient("http://localhost:11434", transport_config=transport)
print(sync_client.list_models())
sync_client.close()
async def run() -> None:
async with AsyncOllamaClient("http://localhost:11434", transport_config=transport) as client:
payload = await client.chat(
model="tinyllama:latest",
messages=[{"role": "user", "content": "hello"}],
stream=False,
)
print(payload)
asyncio.run(run())
4) Ollama streaming chunk API (sync + async)
import asyncio
from llm_telemetry_toolkit import AsyncOllamaClient, OllamaClient
with OllamaClient("http://localhost:11434") as client:
for event in client.stream_generate("tinyllama:latest", "Count 1 to 3"):
print(event)
async def run_stream() -> None:
async with AsyncOllamaClient("http://localhost:11434") as client:
async for event in client.stream_chat(
model="tinyllama:latest",
messages=[{"role": "user", "content": "Say hello in 3 words"}],
):
print(event)
asyncio.run(run_stream())
5) Optional OpenTelemetry export
from llm_telemetry_toolkit import LLMLogger, TelemetryConfig
logger = LLMLogger(
TelemetryConfig(
session_id="otel_demo",
enable_otel_export=True,
otel_tracer_name="research_tool",
otel_span_name="llm.interaction",
otel_service_name="llm-telemetry-toolkit",
otel_auto_configure=True,
otel_otlp_endpoint="http://localhost:4318/v1/traces",
otel_sampler_ratio=1.0,
)
)
Note: OTel export is additive to file logging and uses
opentelemetry-api/sdk+ OTLP exporter when auto-configure is enabled.
Commands & Arguments
CLI entry points
llm-telemetry-toolkit ...python -m llm_telemetry_toolkit.interface.cli ...
Commands
view
Render recent interactions for a session.
llm-telemetry-toolkit view --session <SESSION_ID> [--dir ./logs] [--limit 5]
Arguments:
--session(required): session id folder underllm_interactions/--dir(optional): base log directory (default:./logs)--limit(optional): number of latest interactions to display (default:5)
stats
Aggregate totals (latency, token counts, cost, model usage).
llm-telemetry-toolkit stats --session <SESSION_ID> [--dir ./logs]
Arguments:
--session(required): session id folder underllm_interactions/--dir(optional): base log directory (default:./logs)
Configuration (TelemetryConfig)
| Field | Type | Default | Notes |
|---|---|---|---|
session_id |
str |
session_YYYYMMDD_HHMMSS |
Required to be non-empty; used in folder routing. |
base_log_dir |
Path |
./logs |
Root location for outputs. |
enable_session_logging |
bool |
True |
Enables primary session logs. |
enable_entity_logging |
bool |
False |
Enables entity-routed logs under entity_log_subdir. |
session_log_subdir |
str |
llm_interactions |
Session output folder name. |
entity_log_subdir |
str |
entity_llm_interactions |
Entity output folder name. |
output_formats |
List[str] |
["json"] |
Supported only: json, md, csv. |
filename_template |
str |
{timestamp}_{interaction_id}_{type}.{ext} |
Supports {timestamp}, {interaction_id}, {type}, {ext}, {session_id}, {model_name}, {tool_name}. |
json_indent |
int |
2 |
Pretty indent for JSON payloads. |
ensure_ascii |
bool |
False |
Controls JSON unicode escaping. |
max_content_length |
Optional[int] |
None |
Truncates prompt/response/thought content. |
mask_pii |
bool |
False |
Redacts email/IP/phone/card patterns. |
enable_otel_export |
bool |
False |
Emits optional OTel spans in addition to file logs. |
otel_tracer_name |
str |
llm_telemetry_toolkit |
Tracer name used for emitted spans. |
otel_span_name |
str |
llm.interaction |
Span operation name for each interaction. |
otel_service_name |
str |
llm-telemetry-toolkit |
Service name attribute on spans. |
otel_auto_configure |
bool |
False |
Bootstraps OTel SDK provider/exporter when no provider is set. |
otel_exporter |
str |
otlp_http |
Auto-config exporter (otlp_http or none). |
otel_otlp_endpoint |
str |
http://localhost:4318/v1/traces |
OTLP/HTTP destination endpoint. |
otel_otlp_headers |
Dict[str, str] |
{} |
Optional headers (auth/tenant). |
otel_otlp_timeout_seconds |
float |
10.0 |
OTLP export timeout in seconds. |
otel_enable_console_export |
bool |
False |
Emit spans to console in addition to OTLP. |
otel_sampler_ratio |
float |
1.0 |
Trace sampling ratio for auto-configured SDK. |
otel_resource_attributes |
Dict[str, str] |
{} |
Extra resource attributes on spans. |
Structured interaction fields (LLMInteraction)
In addition to free-form metadata, the schema now supports explicit optional fields for downstream consistency:
- Chat/tooling:
request_messages,response_message_role,finish_reason,tool_calls - Embeddings:
embedding_input_count,embedding_vector_count,embedding_dimensions - Typed helper models:
ChatMessage,ToolCall,ToolFunctionCall
Examples
Decorator-based logging (sync + async)
import asyncio
from llm_telemetry_toolkit import LLMLogger, TelemetryConfig, monitor_interaction
logger = LLMLogger(TelemetryConfig(session_id="decorator_demo"))
@monitor_interaction(logger, interaction_type="sync_call")
def multiply(x: int, y: int) -> int:
return x * y
@monitor_interaction(logger, interaction_type="async_call")
async def async_multiply(x: int, y: int) -> int:
await asyncio.sleep(0.05)
return x * y
print(multiply(3, 4))
print(asyncio.run(async_multiply(5, 6)))
logger.shutdown()
True sync writes (for strict confirmation paths)
from llm_telemetry_toolkit import LLMInteraction, LLMLogger, TelemetryConfig
logger = LLMLogger(TelemetryConfig(session_id="sync_demo"))
result = logger.log(
LLMInteraction(
session_id="sync_demo",
model_name="sync-model",
prompt="hello",
response="world",
response_time_seconds=0.1,
),
sync=True,
)
print(result.success, result.queued, result.write_confirmed, result.created_files)
logger.shutdown()
Testing
Standard local test run
python -B -m pytest -q
Optional live Ollama integration test (private/local only)
- Copy
settings.example.cfgtosettings.cfg. - Update
settings.cfgwith your private local server values. - Run:
$env:OLLAMA_INTEGRATION = "1"
python -m pytest tests/test_ollama_integration.py -q
Packaging & Release Notes
- Versioning is VCS-driven via
hatch-vcsand git tags (vX.Y.Z). - Console script entry point is published as
llm-telemetry-toolkit. - PyPI publish workflow is tag-triggered (
pushonv*tags). - Optional TestPyPI publish can be run manually via GitHub Actions workflow dispatch.
Recommended release sequence:
- Dry run preflight:
python .\tools\publish_release.py --project .\llm-telemetry-toolkit --version 0.2.0 --dry-run
- Real release tag push:
python .\tools\publish_release.py --project .\llm-telemetry-toolkit --version 0.2.0
- (Optional) Manual TestPyPI publish from Actions UI:
- Workflow:
Publish to PyPI - Input:
publish_target = testpypi
- Workflow:
Author & Links
Created by Roy Dawson IV
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llm_telemetry_toolkit-0.2.1.tar.gz.
File metadata
- Download URL: llm_telemetry_toolkit-0.2.1.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea5ccc2de789eaba0416f4666c8119afec763d777c72a3000ec4ba3e952a40d2
|
|
| MD5 |
5087c44cd24478a9ba6aec1d26e9f6f2
|
|
| BLAKE2b-256 |
c2e08e7a22715dbb069faac45adc804854f9325dd864ff482746119b910a8b89
|
Provenance
The following attestation bundles were made for llm_telemetry_toolkit-0.2.1.tar.gz:
Publisher:
python-publish.yml on ImYourBoyRoy/llm-telemetry-toolkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_telemetry_toolkit-0.2.1.tar.gz -
Subject digest:
ea5ccc2de789eaba0416f4666c8119afec763d777c72a3000ec4ba3e952a40d2 - Sigstore transparency entry: 1004143344
- Sigstore integration time:
-
Permalink:
ImYourBoyRoy/llm-telemetry-toolkit@7aaef83f0c7ae30104bc1a060b091aa0959993e7 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/ImYourBoyRoy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@7aaef83f0c7ae30104bc1a060b091aa0959993e7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file llm_telemetry_toolkit-0.2.1-py3-none-any.whl.
File metadata
- Download URL: llm_telemetry_toolkit-0.2.1-py3-none-any.whl
- Upload date:
- Size: 38.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
feddbf559b0e5a65804a687f5000409c6c81ab5f828a7a0d0529a3c0f3540470
|
|
| MD5 |
105c461aa2427ec19f0cc63167af79fc
|
|
| BLAKE2b-256 |
7888df3d7e43d25c49772b0f1087d7d97bb8a6101272397e43201ef2a4980575
|
Provenance
The following attestation bundles were made for llm_telemetry_toolkit-0.2.1-py3-none-any.whl:
Publisher:
python-publish.yml on ImYourBoyRoy/llm-telemetry-toolkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
llm_telemetry_toolkit-0.2.1-py3-none-any.whl -
Subject digest:
feddbf559b0e5a65804a687f5000409c6c81ab5f828a7a0d0529a3c0f3540470 - Sigstore transparency entry: 1004143345
- Sigstore integration time:
-
Permalink:
ImYourBoyRoy/llm-telemetry-toolkit@7aaef83f0c7ae30104bc1a060b091aa0959993e7 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/ImYourBoyRoy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@7aaef83f0c7ae30104bc1a060b091aa0959993e7 -
Trigger Event:
push
-
Statement type: