Welcome to the first chapter of the Telemetry project tutorial!
Before our application can start recording useful data, we need to set up the recording equipment. In the software world, this setup phase is called Bootstrap & Instrumentation.
Think of your application as a band about to play a concert.
Telemetry Bootstrap is the Sound Check. Before the band starts playing, the sound engineer must:
If you skip the sound check, the band plays in silence.
Imagine you are starting the claude-code CLI tool. You want to answer three questions automatically every time the app runs:
We solve this by creating a centralized initializeTelemetry() function that runs immediately when the app starts.
A Resource describes the environment. Instead of hardcoding "I am a Mac," we use detectors to figure it out dynamically.
There are three main types of telemetry data, each with its own "Provider" (manager):
console.log but better).An Exporter takes the data from the Provider and sends it somewhere.
The following diagram shows what happens inside the telemetry system when the application boots up.
Let's look at how this is implemented in instrumentation.ts. We will break the complex initialization process into small, understandable steps.
First, we gather attributes about the machine. We use standard OpenTelemetry detectors (osDetector, envDetector) and merge them with our own custom attributes.
// From instrumentation.ts
const baseAttributes = {
[ATTR_SERVICE_NAME]: 'claude-code',
[ATTR_SERVICE_VERSION]: MACRO.VERSION,
}
// Create the "Resource" (The identity of the app)
const resource = resourceFromAttributes(baseAttributes)
.merge(osDetector.detect()) // e.g., Windows 11
.merge(hostDetector.detect()) // e.g., x64 architecture
.merge(envDetector.detect()) // e.g., AWS / Local
Next, we decide where the data goes. We look at environment variables (like OTEL_LOGS_EXPORTER). This is like plugging in the cables.
// Helper function to pick the right exporter
async function getOtlpLogExporters() {
const exporterTypes = parseExporterTypes(process.env.OTEL_LOGS_EXPORTER)
const exporters = []
// If environment says "console", use the Console exporter
if (exporterTypes.includes('console')) {
exporters.push(new ConsoleLogRecordExporter())
}
// If environment says "otlp" (network), use the Network exporter
if (exporterTypes.includes('otlp')) {
// Dynamically import the heavy network code only if needed
const { OTLPLogExporter } = await import('@opentelemetry/exporter-logs-otlp-http')
exporters.push(new OTLPLogExporter(getOTLPExporterConfig()))
}
return exporters
}
Note: We use
await import(...)inside theifstatement. This is a performance trick! If we aren't sending network logs, we don't load the heavy network code, making the app start faster.
Now we create the managers (Providers) and give them the Resource (identity) and Exporters (destination).
// From initializeTelemetry()
const meterProvider = new MeterProvider({
resource,
readers: await getOtlpReaders(), // Metric readers
})
// Save this provider globally so we can use it later
setMeterProvider(meterProvider)
// Return the meter so the app can start counting things immediately
return meterProvider.getMeter('com.anthropic.claude_code')
What happens if the user closes the app while we are uploading data? We need to ensure we flush (finish sending) the data before the process dies.
// Define what happens when the app shuts down
const shutdownTelemetry = async () => {
// Stop the music!
endInteractionSpan()
// Force all providers to send their remaining data
await Promise.all([
meterProvider.shutdown(),
loggerProvider?.shutdown(),
tracerProvider?.shutdown()
])
}
// Hook this into the process exit event
registerCleanup(shutdownTelemetry)
You might notice references to initializeBetaTracing in the code. This is a special, parallel system for detailed debugging. It allows developers to turn on "High Definition" recording without affecting the standard telemetry used for general analytics.
We will cover how traces interact with logs in Session Tracing & Context Propagation.
In this chapter, we learned:
Now that our system is initialized and ready to record, we need to understand how to track the user's journey through the application.
Next Chapter: Session Tracing & Context Propagation
Generated by Code IQ