Created
April 14, 2025 21:06
-
-
Save fmhall/5c639adda56d29dd9eb8cf8e01984ad3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
ConsoleSpanExporter, | |
SimpleSpanProcessor, | |
WebTracerProvider, | |
} from '@opentelemetry/sdk-trace-web'; | |
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; | |
import { ZoneContextManager } from '@opentelemetry/context-zone'; | |
import { registerInstrumentations } from '@opentelemetry/instrumentation'; | |
import { context, trace } from '@opentelemetry/api'; | |
// Initialize state for tracing | |
let tracingEnabled = true; | |
let provider: WebTracerProvider; | |
let fetchInstrumentation: FetchInstrumentation; | |
let tracer: any; | |
// Initialize the tracer provider | |
function initTracing() { | |
provider = new WebTracerProvider({ | |
spanProcessors: [new SimpleSpanProcessor(new ConsoleSpanExporter())] | |
}); | |
provider.register({ | |
contextManager: new ZoneContextManager(), | |
}); | |
fetchInstrumentation = new FetchInstrumentation({ | |
// This will track all fetch requests in the application | |
ignoreUrls: [/localhost/], | |
propagateTraceHeaderCorsUrls: [/.*/], | |
clearTimingResources: true, | |
}); | |
registerInstrumentations({ | |
instrumentations: [fetchInstrumentation], | |
}); | |
// Create a tracer | |
tracer = provider.getTracer('example-tracer'); | |
console.log('OpenTelemetry tracing initialized and enabled'); | |
} | |
// Disable tracing | |
function disableTracing() { | |
if (fetchInstrumentation) { | |
fetchInstrumentation.disable(); | |
} | |
tracingEnabled = false; | |
console.log('OpenTelemetry tracing disabled'); | |
} | |
// Enable tracing | |
function enableTracing() { | |
if (!provider) { | |
initTracing(); | |
} else if (fetchInstrumentation) { | |
fetchInstrumentation.enable(); | |
} | |
tracingEnabled = true; | |
console.log('OpenTelemetry tracing enabled'); | |
} | |
// Toggle tracing state | |
export function toggleTracing() { | |
if (tracingEnabled) { | |
disableTracing(); | |
return false; | |
} else { | |
enableTracing(); | |
return true; | |
} | |
} | |
// === Test functions for different header types === | |
// Case 1: Regular object headers | |
function makeFetchRequestWithObjectHeaders() { | |
return fetch('https://httpbin.org/get', { | |
headers: { | |
'X-Custom-Object-Header': 'test-object-header', | |
'privy-app-id': 'object-privy-id', | |
'X-B3-TraceId': 'test-trace-id', | |
'X-B3-SpanId': 'test-span-id' | |
} | |
}); | |
} | |
// Case 2: Headers instance | |
function makeFetchRequestWithHeadersInstance() { | |
const headers = new Headers(); | |
headers.append('X-Custom-Headers-Instance', 'test-headers-instance'); | |
headers.append('privy-app-id', 'headers-privy-id'); | |
headers.append('X-B3-TraceId', 'test-trace-id'); | |
headers.append('X-B3-SpanId', 'test-span-id'); | |
return fetch('https://httpbin.org/get', { headers }); | |
} | |
// Case 3: Map instance | |
function makeFetchRequestWithMapHeaders() { | |
// Convert Map to a regular object for Headers compatibility | |
const mapHeaders = new Map(); | |
mapHeaders.set('X-Custom-Map-Header', 'test-map-header'); | |
mapHeaders.set('privy-app-id', 'map-privy-id'); | |
mapHeaders.set('X-B3-TraceId', 'test-trace-id'); | |
mapHeaders.set('X-B3-SpanId', 'test-span-id'); | |
// Convert Map to Headers | |
const headers = new Headers(); | |
mapHeaders.forEach((value, key) => { | |
headers.append(key.toString(), value.toString()); | |
}); | |
return fetch('https://httpbin.org/get', { headers }); | |
} | |
// Case 4: Custom header object with getters | |
function makeFetchRequestWithGetterHeaders() { | |
const headers = { | |
get 'X-Custom-Getter-Header'() { return 'test-getter-header'; }, | |
get 'privy-app-id'() { return 'getter-privy-id'; }, | |
get 'X-B3-TraceId'() { return 'test-trace-id'; }, | |
get 'X-B3-SpanId'() { return 'test-span-id'; } | |
}; | |
return fetch('https://httpbin.org/get', { headers }); | |
} | |
// Case 5: Workaround with spread operator | |
function makeFetchRequestWithSpreadHeaders() { | |
const options = { method: 'GET' }; | |
const headers = { | |
'X-Custom-Spread-Header': 'test-spread-header', | |
'privy-app-id': 'spread-privy-id', | |
'X-B3-TraceId': 'test-trace-id', | |
'X-B3-SpanId': 'test-span-id' | |
}; | |
return fetch('https://httpbin.org/get', { | |
...options, | |
headers | |
}); | |
} | |
// Standard fetch function (used for the basic case) | |
function makeFetchRequest() { | |
return fetch('https://httpbin.org/get', { | |
headers: { | |
'privy-app-id': 'basic-privy-id', | |
'X-B3-TraceId': "test", | |
'X-B3-SpanId': "test" | |
}, | |
}); | |
} | |
// Header test cases | |
type HeaderTestType = 'Object Headers' | 'Headers Instance' | 'Map Headers' | 'Getter Headers' | 'Spread Headers' | 'Basic Headers'; | |
const headerTestCases: Record<HeaderTestType, () => Promise<Response>> = { | |
"Object Headers": makeFetchRequestWithObjectHeaders, | |
"Headers Instance": makeFetchRequestWithHeadersInstance, | |
"Map Headers": makeFetchRequestWithMapHeaders, | |
"Getter Headers": makeFetchRequestWithGetterHeaders, | |
"Spread Headers": makeFetchRequestWithSpreadHeaders, | |
"Basic Headers": makeFetchRequest | |
}; | |
// Export function to make a fetch request | |
export function makeTracedFetchRequest(headerType: HeaderTestType = 'Basic Headers') { | |
const fetchFunction = headerTestCases[headerType] || makeFetchRequest; | |
if (!tracingEnabled) { | |
console.log(`Making untraced fetch request with ${headerType} (tracing is disabled)`); | |
return fetchFunction(); | |
} | |
// Create a span for our test | |
const span = tracer.startSpan(`test-fetch-${headerType}`); | |
// Use the context to ensure the span is properly associated with the fetch | |
return context.with(trace.setSpan(context.active(), span), async () => { | |
try { | |
// Perform the fetch operation | |
console.log(`Making traced fetch request with ${headerType}`); | |
const response = await fetchFunction(); | |
console.log('Fetch status:', response.status); | |
return response; | |
} catch (error) { | |
console.error('Fetch error:', error); | |
throw error; | |
} finally { | |
// End the span | |
span.end(); | |
} | |
}); | |
} | |
// Initialize the application | |
function initApp() { | |
// Initialize tracing on start | |
initTracing(); | |
// Add event listener to the toggle button | |
const toggleButton = document.getElementById('toggleTracing'); | |
if (toggleButton) { | |
toggleButton.addEventListener('click', () => { | |
const isEnabled = toggleTracing(); | |
toggleButton.textContent = isEnabled ? 'Tracing: Enabled' : 'Tracing: Disabled'; | |
toggleButton.classList.toggle('active', isEnabled); | |
}); | |
// Set initial state | |
toggleButton.classList.toggle('active', tracingEnabled); | |
} | |
// Add event listener to the request button | |
const requestButton = document.getElementById('makeRequest'); | |
if (requestButton) { | |
requestButton.addEventListener('click', async () => { | |
// Get the selected header type | |
const headerTypeSelect = document.getElementById('headerType') as HTMLSelectElement; | |
const headerType = headerTypeSelect ? | |
(headerTypeSelect.value as HeaderTestType) : 'Basic Headers'; | |
console.log(`Making fetch request with ${headerType}...`); | |
try { | |
const response = await makeTracedFetchRequest(headerType); | |
const data = await response.json(); | |
// Display status and data | |
const statusElement = document.getElementById('status'); | |
if (statusElement) { | |
statusElement.innerHTML = ` | |
<h3>Response with ${headerType}:</h3> | |
<pre>${JSON.stringify(data, null, 2)}</pre> | |
<p>Tracing: ${tracingEnabled ? 'Enabled' : 'Disabled'}</p> | |
`; | |
} | |
} catch (error) { | |
console.error('Error making request:', error); | |
} | |
}); | |
} | |
} | |
// Initialize when DOM is loaded | |
window.addEventListener('DOMContentLoaded', initApp); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment