Use one canonical operation event
Do not emitstarted, processing, and completed logs for routine work. Keep child work as spans. Keep counters and durations as metrics. Emit one final operation event in a finally block.
Use stable field names
Use low-cardinality fields such as route, region, provider, result, and release for breakdowns. Use high-cardinality fields such as request, user, order, or monitor IDs only for direct filtering. Do not group large time windows by a unique ID.
Keep attribute types
Send numbers and booleans as numbers and booleans. The JavaScript SDKs flatten safe nested objects to dotted keys.cache.hit=true, cache.age_ms=42, and result_count=8. Sensitive attribute names, such as passwords, tokens, cookies, and authorization values, are redacted. Attribute depth, count, and string length are bounded.
Sample by outcome
Use deterministic outcome-aware sampling. Keep failures and slow operations. Sample routine success. Squasher keeps operation measurements when it samples out the related log and trace, so counts and latency data stay exact.Protect private data
- Do not record credentials, session cookies, raw authorization headers, prompts, or payment data.
- Record route templates instead of raw URLs with customer identifiers.
- Put an internal ID in an attribute only when an operator must find one exact operation.
- Use
beforeSendfor product-specific redaction and allowlists.
Verify quality
For each service, check that operation events have service, environment, release, route or operation, outcome, status, duration, and trace correlation. Also check for orphan logs, duplicate final events, and attribute type changes. Use the Logs API for narrow searches and the Logs Patterns and Changes views for bounded comparisons. Runsquasher observe quality --project <project_id> --service-name <service>
or use the Telemetry Quality API for a
content-free, bounded report of these checks.