-
-
Save uzimith/7d0048852e717ef7d993aeffc238d18f to your computer and use it in GitHub Desktop.
otel-hello
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 { resourceFromAttributes } from "@opentelemetry/resources"; | |
| import { | |
| ATTR_SERVICE_NAME, | |
| ATTR_SERVICE_VERSION, | |
| } from "@opentelemetry/semantic-conventions"; | |
| import { NodeSDK } from "@opentelemetry/sdk-node"; | |
| import { trace, SpanStatusCode } from "@opentelemetry/api"; | |
| import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http"; | |
| interface ParsedArgs { | |
| otelEndpoint: string | null; | |
| names: string[]; | |
| } | |
| function parseArgs(argv: string[]): ParsedArgs { | |
| const args = argv.slice(2); | |
| let otelEndpoint: string | null = null; | |
| const names: string[] = []; | |
| for (let i = 0; i < args.length; i++) { | |
| if (args[i] === "--otel") { | |
| otelEndpoint = args[++i]; | |
| if (!otelEndpoint) { | |
| console.error("Error: --otel requires an endpoint URL"); | |
| process.exit(1); | |
| } | |
| } else if (args[i] === "--help" || args[i] === "-h") { | |
| console.log( | |
| `Usage: npx tsx src/main.ts [--otel <endpoint>] [name...] | |
| --otel <endpoint> OTLP HTTP endpoint (e.g. http://localhost:4318/) | |
| name Names to greet (default: "World")`, | |
| ); | |
| process.exit(0); | |
| } else { | |
| names.push(args[i]); | |
| } | |
| } | |
| if (names.length === 0) { | |
| names.push("World"); | |
| } | |
| return { otelEndpoint, names }; | |
| } | |
| function setupSDK(endpoint: string): NodeSDK { | |
| const sdk = new NodeSDK({ | |
| resource: resourceFromAttributes({ | |
| [ATTR_SERVICE_NAME]: "otel-sample", | |
| [ATTR_SERVICE_VERSION]: "1.0", | |
| }), | |
| traceExporter: new OTLPTraceExporter({ | |
| url: new URL("/v1/traces", endpoint).toString(), | |
| }), | |
| }); | |
| sdk.start(); | |
| return sdk; | |
| } | |
| // setupSDK() を呼び出す前に tracer を取得しても、SDK の start() 後に SDK で登録されたトレーサープロバイダーが使用される | |
| const tracer = trace.getTracer("otel-sample", "1.0"); | |
| async function greet(name: string): Promise<void> { | |
| await tracer.startActiveSpan(`greet:${name}`, async (span) => { | |
| const delaySec = Math.random() * 2; | |
| span.setAttribute("delay_sec", delaySec); | |
| span.setAttribute("name", name); | |
| await new Promise((resolve) => setTimeout(resolve, delaySec * 1000)); | |
| console.log(`Hello, ${name}!`); | |
| if (delaySec > 1) { | |
| const err = new Error(`Too slow: ${delaySec.toFixed(2)}s`); | |
| span.recordException(err); | |
| span.setStatus({ | |
| code: SpanStatusCode.ERROR, | |
| message: err.message, | |
| }); | |
| span.end(); | |
| throw err; | |
| } | |
| span.end(); | |
| }); | |
| } | |
| async function greets(names: string[]): Promise<void> { | |
| await tracer.startActiveSpan("greets", async (span) => { | |
| let hasError = false; | |
| for (const name of names) { | |
| try { | |
| await greet(name); | |
| } catch { | |
| console.log(`Failed to hello ${name}`); | |
| hasError = true; | |
| } | |
| } | |
| if (hasError) { | |
| span.setStatus({ | |
| code: SpanStatusCode.ERROR, | |
| message: "Some greetings failed", | |
| }); | |
| } | |
| span.end(); | |
| }); | |
| } | |
| function finish(): void { | |
| tracer.startActiveSpan("finish", (span) => { | |
| console.log("Done!"); | |
| span.end(); | |
| }); | |
| } | |
| async function cliRun(names: string[]): Promise<void> { | |
| await tracer.startActiveSpan("cli-run", async (span) => { | |
| span.setAttribute("args.names", names.join(", ")); | |
| try { | |
| await greets(names); | |
| finish(); | |
| } catch (err) { | |
| if (err instanceof Error) { | |
| span.recordException(err); | |
| } | |
| span.setStatus({ | |
| code: SpanStatusCode.ERROR, | |
| message: err instanceof Error ? err.message : String(err), | |
| }); | |
| throw err; | |
| } finally { | |
| span.end(); | |
| } | |
| }); | |
| } | |
| async function main() { | |
| const parsed = parseArgs(process.argv); | |
| const sdk = parsed.otelEndpoint ? setupSDK(parsed.otelEndpoint) : null; | |
| try { | |
| await cliRun(parsed.names); | |
| } finally { | |
| if (sdk) { | |
| // トレースの送信を保証する | |
| await sdk.shutdown(); | |
| } | |
| } | |
| } | |
| main().catch((err) => { | |
| console.error(err); | |
| process.exit(1); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment