Skip to main content

Network Instrumentation

Generates: Spans

Automatically instruments HTTP requests made via OkHttp and HttpURLConnection.

How It Works

Pulse Android SDK automatically instruments HTTP requests when using:

  • OkHttp 3.0+ - Most popular HTTP client library for Android
  • HttpURLConnection - Standard Java HTTP client
  • HttpsURLConnection - Secure HTTP connections

The instrumentation operates by intercepting application calls to these APIs, creating client HTTP spans with request/response metadata.

Quick Start

Add these dependencies to your project

Replace BYTEBUDDY_VERSION with the latest release.

Byte buddy compilation plugin

This plugin leverages Android's Transform API to instrument bytecode at compile time. You can find more info on its repo page.

Root Project dependencies

plugins {
id("net.bytebuddy.byte-buddy-gradle-plugin") version "BYTEBUDDY_VERSION"
}

Project dependencies

// if you are using OkHttp then use below libraries
implementation("in.horizonos.instrumentation:okhttp3-library:0.0.1-alpha")
byteBuddy("in.horizonos.instrumentation:okhttp3-agent:0.0.1-alpha")

// for httpurlconnection
implementation("in.horizonos.instrumentation:httpurlconnection-library:0.0.1-alpha")
byteBuddy("in.horizonos.instrumentation:httpurlconnection-agent:0.0.1-alpha")

After adding the plugin and the dependencies to your project, your OkHttp requests will be traced automatically.

Configuration

Network instrumentation is enabled by default when using the Android agent. You can configure it during SDK initialization:

PulseSDK.INSTANCE.initialize(
application = this,
endpointBaseUrl = "https://your-backend.com",
) {
network {
enabled(true) // Enabled by default
}
}

What Gets Tracked

All HTTP requests are automatically captured, including:

  • OkHttp requests (OkHttp 3.0+)
  • HttpURLConnection requests
  • HttpsURLConnection requests

Each network request automatically captures HTTP method, URL, status code, protocol version, server information, headers, and error details. See the Attributes section below for complete details.

Generated Telemetry

Type: Span
Span Name: HTTP {method} (e.g., HTTP GET, HTTP POST)
Span Kind: CLIENT
pulse.type: network

Attributes

Network-Specific Attributes

AttributeDescriptionExampleAlways Present
pulse.typeInstrumentation type"network"✅ Yes
http.methodHTTP method"GET", "POST"✅ Yes
http.urlNormalized request URL See URL Normalization for details on how URLs are normalized."https://api.example.com/users/[redacted]"✅ Yes
http.schemeURL scheme"https"⚠️ Only if URL is parseable
http.hostRequest hostname"api.example.com"⚠️ Only if URL is parseable
http.targetRequest path"/users/123"⚠️ Only if URL is parseable
http.flavorProtocol version"1.1", "2.0"⚠️ Only if available
http.status_codeResponse status code200, 404, 500⚠️ Only if response received
net.peer.nameServer hostname"api.example.com"⚠️ Only if URL is parseable
net.peer.portPort number443, 8080⚠️ Only if URL contains port

Error Attributes (on failure)

AttributeDescriptionExample
errorError flagtrue
exception.typeException class name"java.net.SocketTimeoutException"
exception.messageException message"Connection timed out"

Note: The SDK automatically records exceptions on spans when network requests fail, following OpenTelemetry semantic conventions.

URL Normalization

The Pulse Android SDK automatically normalizes URLs in the http.url attribute to protect sensitive data and improve aggregation. URL normalization applies the following transformations:

Normalization Process

  1. Query Parameters Removal: All query parameters are removed from the URL before normalization patterns are applied.

    • Original: https://api.example.com/users/123?token=abc&page=1
    • Normalized: https://api.example.com/users/123 (before pattern matching)
  2. Pattern-Based Redaction: The following patterns in URL path segments are replaced with [redacted]:

PatternDescriptionExampleNormalized Result
64-character hex stringsSHA-256 hashes/api/files/a1b2c3d4e5f6... (64 hex chars)/api/files/[redacted]
40-character hex stringsSHA-1 hashes/api/commits/abc123... (40 hex chars)/api/commits/[redacted]
32-character hex stringsMD5 hashes or short IDs/api/sessions/def456... (32 hex chars)/api/sessions/[redacted]
UUID format8-4-4-4-12 hex pattern/api/users/550e8400-e29b-41d4-a716-446655440000/api/users/[redacted]
24-character hex stringsMongoDB ObjectIds, etc./api/documents/507f1f77bcf86cd799439011/api/documents/[redacted]
26-character ULIDULID identifiers/api/orders/01ARZ3NDEKTSV4RRFFQ69G5FAV/api/orders/[redacted]
3+ digit numbersNumeric IDs (user IDs, order IDs, etc.)/api/users/12345/api/users/[redacted]
16+ character alphanumericLong alphanumeric IDs/api/tokens/AbC123XyZ789QwE456/api/tokens/[redacted]

Rationale for Normalization Patterns

  • 64/40/32/24-character hex strings: These typically represent cryptographic hashes (SHA-256, SHA-1, MD5) or database IDs (MongoDB ObjectIds) that are unique identifiers and don't provide meaningful aggregation value.

  • UUID format: Universally Unique Identifiers are designed to be unique and don't benefit from being stored as-is in telemetry.

  • ULID (26 characters): Time-ordered unique identifiers that are unique per entity and don't aggregate well.

  • 3+ digit numbers: Numeric IDs with 3 or more digits are commonly used for:

    • User IDs (e.g., /users/12345)
    • Order IDs (e.g., /orders/999)
    • Resource IDs (e.g., /posts/456)

    These IDs are typically unique per entity and can contain sensitive information. Normalizing them allows for better aggregation of similar endpoints while protecting user privacy. Numbers with fewer than 3 digits (like /api/v1 or /api/v2) are preserved as they often represent version numbers or small enumerations that are useful for aggregation.

  • 16+ character alphanumeric strings: Long alphanumeric identifiers are often tokens, session IDs, or other sensitive identifiers that should be redacted.

Note: The normalization only affects the http.url attribute. Other attributes like http.target may still contain the original path with query parameters, depending on how the URL is parsed.

Sample Payload: Successful Network Request

{
"name": "HTTP GET",
"kind": "CLIENT",
"startTimeUnixNano": "1701000020000000000",
"endTimeUnixNano": "1701000020317250000",
"duration": "317.25ms",
"attributes": {
"pulse.type": "network",
"http.method": "GET",
"http.url": "https://api.example.com/users/[redacted]",
"http.scheme": "https",
"http.host": "api.example.com",
"http.target": "/users/123",
"http.status_code": 200,
"http.flavor": "1.1",
"net.peer.name": "api.example.com",
"net.peer.port": 443
}
}

Sample Payload: Failed Network Request

{
"name": "HTTP POST",
"kind": "CLIENT",
"status": "ERROR",
"startTimeUnixNano": "1701000030000000000",
"endTimeUnixNano": "1701000030500000000",
"duration": "50ms",
"attributes": {
"pulse.type": "network",
"http.method": "POST",
"http.url": "https://api.example.com/orders",
"http.scheme": "https",
"http.host": "api.example.com",
"http.target": "/orders",
"http.status_code": 0,
"net.peer.name": "api.example.com",
"error": true,
"exception.type": "java.net.SocketTimeoutException",
"exception.message": "Connection timed out"
}
}

Global Attributes

All network spans include global attributes (service, device, OS, session, network carrier, etc.). See Global Attributes for complete list.