Logs and telemetry
Every part of Datanotes sends its logs with OpenTelemetry, the vendor-neutral standard: OTLP
over HTTP to <endpoint>/v1/logs, encoded as http/protobuf (the OpenTelemetry default) or
http/json. Any OpenTelemetry Collector and any backend with an OTLP endpoint receives them —
for example SigNoz, Grafana (Alloy, Loki, Grafana Cloud), Elastic, Datadog, Honeycomb, New Relic,
Dynatrace or a self-hosted OpenTelemetry Collector. There is no vendor-specific code.
Only logs are sent (no traces or metrics), and only over HTTP: for a backend that takes gRPC only, put an OpenTelemetry Collector in front. When the collector does not answer, records are counted as lost and nothing else is affected.
Standard configuration
Section titled “Standard configuration”The engine, the MCP server and the apps all read the standard OpenTelemetry variables:
| Variable | Meaning |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
the collector’s base address, e.g. http://127.0.0.1:4318 |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT |
or the full …/v1/logs address |
OTEL_EXPORTER_OTLP_HEADERS |
key=value,key2=value2 (values URL-encoded): the API key or Authorization your backend asks for |
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf (default) or http/json |
OTEL_SERVICE_NAME |
the service name (defaults: datanotes, datanotes-mcp, the app’s name) |
OTEL_RESOURCE_ATTRIBUTES |
extra resource attributes, e.g. deployment.environment=home |
OTEL_SDK_DISABLED=true or OTEL_LOGS_EXPORTER=none |
turn export off |
The …_LOGS_… variants of headers and protocol are read too. Without an endpoint nothing is sent.
The engine’s settings
Section titled “The engine’s settings”Instead of the variables, the engine can be configured in its settings file
(<vault>/.datanotes/service.json); the variables, when set, take precedence:
{ "telemetryEnabled": true, "telemetryEndpoint": "http://127.0.0.1:4318", "telemetryServiceName": "datanotes", "telemetryProtocol": "http/protobuf", "telemetryHeaders": {}}telemetryHeaders holds what the backend asks for (an API key, Authorization: Bearer …). It is
kept in the settings file: to keep a key out of it, use OTEL_EXPORTER_OTLP_HEADERS.
The engine also writes its records to <vault>/.datanotes/logs/ (fileLogEnabled, kept
logRetentionDays), whatever the collector does.
What the engine logs: every HTTP request and operation (route, duration, outcome, the actor), the tool calls MCP servers report (tool, duration, result size in characters and tokens, client, model, session), refused requests, the semantic index, git sync, and errors.
The MCP server and the apps
Section titled “The MCP server and the apps”datanotes-mcp: the variables above, or--otlp-endpoint <url>.- The apps: the variables above, or an
otlpblock in the app’s configuration:{"endpoint": "http://127.0.0.1:4318", "headers": {}, "serviceName": "…"}.
Following one call
Section titled “Following one call”The engine, the MCP server and the apps log the same session (the first 16 characters of the MCP
session id) and tool for an agent’s call: filter by session in your backend to see the call in
the MCP server, the app tool it reached, and the writes it made in the engine.
From your own program
Section titled “From your own program”datanotes/client exports the exporter they use:
import { OtlpLogExporter, otlpFromEnv } from "datanotes/client";
const otlp = otlpFromEnv(process.env, { serviceName: "my-app" });const log = otlp ? new OtlpLogExporter(otlp) : null;log?.log("INFO", "imported receipts", { count: 12 });await log?.close(); // before exit