SDK Doctor
Validate the installed Neatlogs SDK locally, then verify one controlled trace through the hosted trace pipeline.
SDK Doctor answers two different questions without editing your application:
- Local: can this installed SDK create, normalize, mask, validate, and flush a controlled trace in memory?
- Probe: can the same installed SDK send a controlled trace through the normal write path and read that exact finalized trace back with the same project key?
These checks are intentionally separate from verification of your real user workflow. A synthetic Doctor probe can prove the telemetry path works, but it cannot prove that your application's entry point, wrappers, hooks, or shutdown behavior are correct.
Use a Doctor-capable SDK
Use the latest published stable SDK from the language's package registry. Do not pin one patch release as the complete support list. A compatible SDK Doctor must emit all of these values:
format_version: "neatlogs.doctor/v2"- the project's language in
runtime.language runtime.schema_version: "2"
Run Doctor from the application root through the active Python interpreter,
the detected Node package manager, or a Go binary built from the project's
resolved module version. Compare runtime.sdk_version with the installed
project package or module to make sure that the command did not select another
copy.
If the installed SDK does not expose Doctor v2, check the canonical registry for the latest published stable release. Upgrade only with your normal package manager and your approval. Accept a newer compatible release and never downgrade it. If the latest stable release still lacks Doctor v2, stop and use manual or support-led remediation instead of a development build.
Install the Go CLI at the project module version
Adding the Go module to go.mod does not install the neatlogs command. First,
read the project's resolved module version:
go list -m -f '{{.Version}}' github.com/neatlogs/neatlogs-goReplace <resolved-module-version> below with that exact result. Review and
approve the command before running it:
go install github.com/neatlogs/neatlogs-go/cmd/neatlogs@<resolved-module-version>Do not use go run, @latest, or an unversioned download as a substitute. Run
local Doctor after installation and require the binary and project module
versions to match.
Fail closed when the command is absent, the JSON is invalid, or the Doctor reports the wrong format, language, schema, or installed-package identity. Do not edit instrumentation until local Doctor passes.
Local mode
Run local Doctor before changing instrumentation:
python -m neatlogs doctor --local --jsonLocal mode is read-only and network-free. It requires no project credential and uses generated, non-user content. It validates the SDK's controlled in-process capture, including IDs, one root, hierarchy, semantic kinds, JSON input/output, sampling, masking boundary, and flush outcome.
A local pass proves the installed SDK can produce a valid controlled envelope. It does not prove any of the following:
- your application is instrumented;
- your real workflow ran;
- the exporter reached Neatlogs;
- the backend finalized a trace; or
- the trace is visible to the project.
Probe mode
Probe mode requires a project key. Put NEATLOGS_API_KEY in your shell, service,
or CI secret store and inject it as an environment variable. Do not put the key
in a command argument, source file, committed .env file, log, support message,
or Doctor JSON. Local mode should be run without adding any credential.
Then run the installed SDK's probe command:
python -m neatlogs doctor --probe --jsonThe probe uses the same project key for both operations:
installed SDK
→ POST /v1/traces with x-neatlogs-doctor: v1
→ normal trace processing
→ GET /api/traces/v3/{trace_id}
→ exact finalized trace validationThe marker identifies controlled Doctor traffic. It does not bypass normal authentication, select a project, or create a privileged processing path.
The controlled trace
Every passing probe must read back exactly this meaningful hierarchy:
doctor.probe.root (WORKFLOW)
├── doctor.probe.agent (AGENT)
│ └── doctor.probe.llm (LLM)
└── doctor.probe.tool (TOOL)A pass requires all of these conditions:
- the captured and read-back trace IDs match exactly;
- the trace is finalized and visible through the authenticated product read path;
- there are exactly four spans, one meaningful root, and no duplicate spans;
- names, kinds, parents, required attributes, input/output, and SDK metadata match the fixture; and
- token values remain JSON numbers. The deterministic fixture is 11 prompt, 7 completion, and 18 total tokens.
An exporter flush or an HTTP 2xx response does not establish these facts. Flush only reports a client-side drain attempt, while HTTP acceptance does not prove finalization or exact authenticated readback.
Result JSON
Doctor writes one sanitized result to stdout. Messages and details contain
public diagnostic facts only; they do not contain credentials, user prompts,
raw response bodies, or private service topology.
{
"format_version": "neatlogs.doctor/v2",
"mode": "probe",
"status": "pass",
"first_failure": null,
"runtime": {
"language": "go",
"sdk_version": "0.1.7",
"schema_version": "2",
"transport": "otlp_http_protobuf"
},
"capture": {
"trace_id": "22222222222222222222222222222222",
"root_span_id": "2222222222222222",
"span_count": 4,
"semantic_digest": "sha256:2222222222222222222222222222222222222222222222222222222222222222"
},
"flush": {
"outcome": "success",
"timeout_ms": 5000,
"duration_ms": 18
},
"probe": {
"ingest_route": "/v1/traces",
"marker_header": "x-neatlogs-doctor",
"marker_version": "v1",
"visible": true,
"readback_trace_id": "22222222222222222222222222222222",
"finalized": true,
"readback_span_count": 4,
"meaningful_root_count": 1,
"duplicate_span_count": 0,
"hierarchy_valid": true,
"attributes_valid": true,
"input_output_valid": true,
"metadata_valid": true,
"typed_tokens_valid": true
},
"checks": [
{
"name": "probe_readback",
"status": "pass",
"reason_code": "HIERARCHY_VALID",
"message": "The persisted four-span hierarchy is valid",
"remediation_code": "NONE"
},
{
"name": "probe_typed_tokens",
"status": "pass",
"reason_code": "TYPED_TOKENS_VALID",
"message": "The persisted token values remain numeric",
"remediation_code": "NONE",
"details": {
"prompt_tokens": 11,
"completion_tokens": 7,
"total_tokens": 18
}
}
]
}first_failure is the reason_code of the first failed check. Warning results
have first_failure: null. Reason and remediation codes are open-ended so newer
SDKs can add codes without breaking older consumers. Preserve an unknown code
and use manual or support-led remediation; do not guess an automatic fix.
Exit statuses
Python, TypeScript, and Go use the same CLI status meanings:
| Exit | Meaning |
|---|---|
0 | All required checks for the selected mode passed. |
1 | Local checks completed with a warning; review it before continuing. |
2 | Local capture or validation failed. |
3 | The authenticated probe failed or remained unverified. |
4 | The command or mode arguments were invalid. |
Always use the JSON status, first_failure, and checks as the diagnostic
record. The process exit status is only a compact automation signal.
Reason-code guide
The exact result is authoritative. These public reason codes are stable; additional codes may be added over time. Common families include:
| Codes | What to check |
|---|---|
INSTRUMENTOR_INACTIVE, PROVIDER_OWNERSHIP_AMBIGUOUS | Initialization and capture ownership. Do not add a second wrapper or provider blindly. |
TRACE_ID_INVALID, SPAN_ID_INVALID, SPAN_ID_DUPLICATE | Trace/span identity in the controlled local envelope. |
PARENT_ID_INVALID, PARENT_MISSING, ROOT_MISSING, ROOT_MULTIPLE, ROOT_NOT_ENDED | Parent propagation, one meaningful root, and span lifecycle. |
INPUT_JSON_INVALID, OUTPUT_JSON_INVALID | Canonical JSON capture before export. |
TOOL_CALL_MISSING, TOOL_EXECUTION_MISSING, CHOICE_LOSS, STREAM_FRAGMENT_MISSING | Semantic fidelity for model output, tools, choices, and streams. |
PAYLOAD_ATTACHMENT_REQUIRED, SAMPLING_INCONSISTENT, FLUSH_TIMEOUT | Payload, trace-level sampling, or bounded drain behavior. |
CREDENTIAL_MISSING, AUTH_FAILED, ENDPOINT_INVALID | Probe credential or endpoint setup. Do not solve these by editing instrumentation. |
BACKEND_PROBE_UNAVAILABLE | The exact trace could not be proved through the normal write/read path. Retry safely or contact support with the reason code and trace ID only. |
Troubleshooting
Command missing or capability unsupported
Confirm the active Python environment, Node lockfile and package manager, or Go module version before changing code. Check the latest stable release in the canonical registry. If an upgrade is available, review the package-manager command before running it. Never downgrade a newer compatible installation. If the latest stable release lacks Doctor v2, stop and contact support instead of downloading another Doctor silently.
Missing credential or authentication failure
Keep the project key in the environment or secret manager. Confirm it belongs
to the project you expect and is available to the Doctor process. Do not paste
it into a command, log, chat, or issue. CREDENTIAL_MISSING means no authenticated
probe could start; AUTH_FAILED means the normal product endpoint rejected the
key.
Timeout, backend unavailability, or finalization delay
BACKEND_PROBE_UNAVAILABLE is not a pass. The SDK may have flushed or received
HTTP acceptance without the exact trace becoming finalized and readable before
the bounded deadline. Retry once with the same installed version and stable
network. Each retry creates new controlled IDs and validates only its own exact
trace. If it repeats, contact support with the SDK version, reason code, and
trace ID; omit credentials and raw payloads.
Hierarchy, duplicates, or token validation failed
Do not rewrite application code to make the synthetic probe pass. Preserve the reported codes and treat this as an SDK or hosted-contract issue. In particular, token counts must remain numeric; a redacted string or numeric-looking string is not equivalent to a number.
Verify the real workflow separately
After local Doctor passes, instrument the application and run its normal approved checks. Run probe mode as the separate controlled pipeline check, then restart any long-running process and exercise one representative user path. Verify the exact resulting project trace and its full finalized span tree.
The three conclusions must remain distinct:
- Local pass: the installed SDK's controlled local envelope is valid.
- Probe pass: the controlled four-span trace survived exact hosted write/finalize/readback verification.
- Real-workflow pass: the application's own exercised path produced the expected finalized user trace without duplicate or missing meaningful spans.
