Last active
June 2, 2024 08:49
-
-
Save liamwh/980b034106030f774a3563ec5fbd441e to your computer and use it in GitHub Desktop.
SvelteKit Otel
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
<script lang="ts"> | |
import type { UserView } from '$lib/stubs/auth'; | |
import { getContext, onMount } from 'svelte'; | |
import { goto } from '$app/navigation'; | |
import { getContacts } from '$lib/repositories/contacts'; | |
import { browser } from '$app/environment'; | |
import { CONTACTS_STORE_KEY, USER_STORE_KEY } from '$lib/store-keys'; | |
import type { Writable } from 'svelte/store'; | |
import AddContactButton from '$lib/components/Contacts/AddContact/AddContactButton.svelte'; | |
import { db } from '$lib/surrealdb'; | |
import type { User } from '$lib/types'; | |
import ContactCard from '$lib/components/Contacts/ContactCard.svelte'; | |
import opentelemetry, { type Span } from '@opentelemetry/api'; | |
import { SpanStatusCode } from '@opentelemetry/api'; | |
import RemoveContactButton from '$lib/components/Contacts/RemoveContact/RemoveContactButton.svelte'; | |
// import { ClientTelemetry } from '$lib/instrumentation/client-telemetry'; | |
const contacts: Writable<User[]> = getContext(CONTACTS_STORE_KEY); | |
const user: Writable<UserView> = getContext(USER_STORE_KEY); | |
async function getContactsAndUpdateStore(userId: string) { | |
const tracer = opentelemetry.trace.getTracer('default'); | |
console.log(tracer); | |
return tracer.startActiveSpan('getContactsAndUpdateStore', async (span) => { | |
try { | |
span.setAttribute('userId', userId); | |
const users = await getContacts(userId); | |
contacts.set(users); | |
span.addEvent('Contacts fetched successfully'); | |
} catch (error) { | |
console.error('Error fetching contacts:', error); | |
if (error instanceof Error) { | |
// Record the exception in the span if it's an Error | |
span.recordException(error); | |
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); | |
} else { | |
// If it's not an Error instance, stringify if possible. | |
span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) }); | |
} | |
contacts.set([]); // Fallback in case of error | |
} finally { | |
console.log(span); | |
span.end(); | |
console.log(span); | |
} | |
}); | |
} | |
async function setupLiveContacts(userId: string) { | |
const tracer = opentelemetry.trace.getTracer('default'); | |
tracer.startActiveSpan('setupLiveContacts', async (span: Span) => { | |
try { | |
await db.live('users', async ({ action, result }) => { | |
if (action === 'CLOSE') return; | |
const updatedUser = result as User; | |
await getContactsAndUpdateStore(userId); | |
console.log(`Contacts updated due to ${action}:`, updatedUser); | |
}); | |
} catch (error) { | |
console.error('Error in live contact update:', error); | |
} finally { | |
span.end(); | |
} | |
}); | |
} | |
onMount(async () => { | |
const currentUser = $user; | |
if (!currentUser) { | |
goto('/login'); | |
} else { | |
await getContactsAndUpdateStore(currentUser.id); | |
await setupLiveContacts(currentUser.id); | |
} | |
}); | |
</script> | |
<!--html here --> |
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 { WebTracerProvider } from '@opentelemetry/sdk-trace-web'; | |
import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; | |
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; | |
import { registerInstrumentations } from '@opentelemetry/instrumentation'; | |
import { ZoneContextManager } from '@opentelemetry/context-zone'; | |
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; | |
import { W3CTraceContextPropagator } from "@opentelemetry/core"; | |
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; | |
import { Resource } from '@opentelemetry/resources'; | |
const TRACE_URL = import.meta.env.VITE_TRACE_URL || 'http://localhost:4318/v1/traces'; | |
const exporter = new OTLPTraceExporter({ | |
url: TRACE_URL, | |
headers: {}, | |
}); | |
const provider = new WebTracerProvider({ | |
resource: new Resource({ | |
[SemanticResourceAttributes.SERVICE_NAME]: 'web-service', | |
}), | |
}); | |
provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); | |
provider.register({ | |
contextManager: new ZoneContextManager(), | |
propagator: new W3CTraceContextPropagator(), | |
}); | |
export class ClientTelemetry { | |
private static instance: ClientTelemetry; | |
private initialized = false; | |
private constructor() {} | |
public static getInstance(): ClientTelemetry { | |
if (!ClientTelemetry.instance) { | |
ClientTelemetry.instance = new ClientTelemetry(); | |
} | |
return ClientTelemetry.instance; | |
} | |
public start() { | |
if (!this.initialized) { | |
registerInstrumentations({ | |
instrumentations: [ | |
getWebAutoInstrumentations(), | |
], | |
}); | |
console.log("Client Telemetry Initialised") | |
this.initialized = true; | |
} | |
} | |
} |
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 type { Handle } from '@sveltejs/kit'; | |
import { Telemetry } from './lib/instrumentation'; | |
export const handle: Handle = async ({ event, resolve }) => { | |
Telemetry.getInstance().start(); | |
return resolve(event); | |
}; |
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 { NodeSDK } from '@opentelemetry/sdk-node'; | |
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; | |
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; | |
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; | |
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; | |
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; | |
import { | |
AlwaysOnSampler, | |
} from '@opentelemetry/sdk-trace-base'; | |
import { Resource } from '@opentelemetry/resources'; | |
const TRACE_URL = import.meta.env.VITE_TRACE_URL || 'http://localhost:4318/v1/traces'; | |
const METRICS_URL = import.meta.env.VITE_METRICS_URL || 'http://localhost:4318/v1/metrics'; | |
const SERVICE_NAME = import.meta.env.VITE_OTEL_SERVICE_NAME || 'veloxide-frontend-localdev'; | |
const exporter = new OTLPTraceExporter({ | |
url: TRACE_URL, | |
headers: {} | |
}); | |
const otelNodeSdk = new NodeSDK({ | |
autoDetectResources: true, | |
serviceName: SERVICE_NAME, | |
traceExporter: exporter, | |
metricReader: new PeriodicExportingMetricReader({ | |
exporter: new OTLPMetricExporter({ | |
url: METRICS_URL, | |
headers: {} | |
}) | |
}), | |
sampler: new AlwaysOnSampler(), | |
resource: new Resource({ | |
[SemanticResourceAttributes.SERVICE_NAME]: SERVICE_NAME | |
}), | |
instrumentations: [ | |
getNodeAutoInstrumentations({ | |
// load custom configuration for http instrumentation | |
'@opentelemetry/instrumentation-http': { | |
applyCustomAttributesOnSpan: (span) => { | |
span.setAttribute('foo2', 'bar2'); | |
} | |
} | |
}) | |
] | |
}); | |
export class Telemetry { | |
private static instance: Telemetry; | |
private initialized = false; | |
private constructor() {} | |
public static getInstance(): Telemetry { | |
if (!Telemetry.instance) { | |
Telemetry.instance = new Telemetry(); | |
} | |
return Telemetry.instance; | |
} | |
public start() { | |
if (!this.initialized) { | |
this.initialized = true; | |
otelNodeSdk.start(); | |
} | |
} | |
} |
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
{ | |
"name": "exampleapp", | |
"version": "0.0.1", | |
"private": true, | |
"scripts": { | |
"dev": "vite dev", | |
"build": "vite build", | |
"preview": "vite preview", | |
"test": "playwright test", | |
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", | |
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", | |
"test:unit": "vitest", | |
"lint": "prettier --plugin-search-dir . --check . && eslint .", | |
"format": "prettier --plugin-search-dir . --write ." | |
}, | |
"devDependencies": { | |
"removed": "removed" | |
}, | |
"type": "module", | |
"dependencies": { | |
"@opentelemetry/api": "^1.7.0", | |
"@opentelemetry/auto-instrumentations-node": "^0.40.1", | |
"@opentelemetry/auto-instrumentations-web": "^0.34.0", | |
"@opentelemetry/context-zone": "^1.18.1", | |
"@opentelemetry/core": "^1.18.1", | |
"@opentelemetry/exporter-metrics-otlp-proto": "^0.45.1", | |
"@opentelemetry/exporter-trace-otlp-http": "^0.45.1", | |
"@opentelemetry/exporter-trace-otlp-proto": "^0.45.1", | |
"@opentelemetry/instrumentation": "^0.45.1", | |
"@opentelemetry/instrumentation-grpc": "^0.45.1", | |
"@opentelemetry/instrumentation-http": "^0.45.1", | |
"@opentelemetry/resources": "^1.18.1", | |
"@opentelemetry/sdk-metrics": "^1.17.1", | |
"@opentelemetry/sdk-node": "^0.44.0", | |
"@opentelemetry/sdk-trace-base": "^1.18.1", | |
"@opentelemetry/sdk-trace-node": "^1.18.1", | |
"@opentelemetry/sdk-trace-web": "^1.18.1", | |
"@opentelemetry/semantic-conventions": "^1.18.1", | |
"...": "..." | |
} | |
} |
I put it in postinstall
so it runs after installing packages. Haven't checked in on this in a while so don't know if it's still necessary.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks! I also found huggingface/chat-ui#1013 useful to figure out I should put the call to this in the
build
script of my package.json.E.g.