diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index 5d9daf752..734681e85 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -9,7 +9,9 @@ "@hydrooj/common": "workspace:^", "@hydrooj/utils": "workspace:^", "@opentelemetry/api": "^1.9.0", + "@opentelemetry/exporter-trace-otlp-grpc": "^0.208.0", "@opentelemetry/exporter-trace-otlp-http": "^0.208.0", + "@opentelemetry/exporter-trace-otlp-proto": "^0.208.0", "@opentelemetry/sdk-node": "^0.208.0", "@zip.js/zip.js": "^2.8.11", "cac": "^6.7.14", diff --git a/packages/hydrojudge/src/config.ts b/packages/hydrojudge/src/config.ts index 51b2b9f27..d44223fa9 100644 --- a/packages/hydrojudge/src/config.ts +++ b/packages/hydrojudge/src/config.ts @@ -33,8 +33,14 @@ export const JudgeSettings = Schema.object({ secret: Schema.string().description('Judge Token Secret').default(randomstring(32)), disable: Schema.boolean().description('Disable builtin judge').default(false), tracing: Schema.object({ + exporter: Schema.union([ + Schema.const('grpc'), + Schema.const('http'), + Schema.const('proto'), + ]).description('Tracing exporter').default('http'), endpoint: Schema.string().role('url').description('Tempo endpoint').default('http://localhost:4318'), samplePercentage: Schema.number().description('Sample percentage').default(0).min(0).max(1), + attributes: Schema.any().description('Tracing attributes').default({}), }), detail: Schema.union([ Schema.const('full'), diff --git a/packages/hydrojudge/src/daemon.ts b/packages/hydrojudge/src/daemon.ts index c4b637c48..794da8d01 100644 --- a/packages/hydrojudge/src/daemon.ts +++ b/packages/hydrojudge/src/daemon.ts @@ -48,7 +48,14 @@ async function daemon() { const shouldRun = await versionCheck((msg) => log.error(msg)); if (!shouldRun) process.exit(1); const tracing = getConfig('tracing'); - if (tracing?.endpoint && tracing?.samplePercentage) initTracing(tracing.endpoint, tracing.samplePercentage); + if (tracing?.endpoint && tracing?.samplePercentage) { + initTracing({ + exporter: tracing.exporter, + endpoint: tracing.endpoint, + samplePercentage: tracing.samplePercentage, + attributes: tracing.attributes, + }); + } const _hosts = getConfig('hosts'); const queue = new PQueue({ concurrency: Infinity }); await fs.ensureDir(getConfig('tmp_dir')); diff --git a/packages/hydrojudge/src/hosts/builtin.ts b/packages/hydrojudge/src/hosts/builtin.ts index a208eb67c..ac311489d 100644 --- a/packages/hydrojudge/src/hosts/builtin.ts +++ b/packages/hydrojudge/src/hosts/builtin.ts @@ -60,7 +60,12 @@ export async function apply(ctx: HydroContext) { const tracing = getConfig('tracing'); if (tracing?.endpoint && tracing?.samplePercentage) { ctx.effect(() => { - const sdk = initTracing(tracing.endpoint, tracing.samplePercentage); + const sdk = initTracing({ + exporter: tracing.exporter, + endpoint: tracing.endpoint, + samplePercentage: tracing.samplePercentage, + attributes: tracing.attributes, + }); return () => sdk.shutdown(); }); } diff --git a/packages/hydrojudge/src/tracing.ts b/packages/hydrojudge/src/tracing.ts index 788479214..6dcda7001 100644 --- a/packages/hydrojudge/src/tracing.ts +++ b/packages/hydrojudge/src/tracing.ts @@ -1,17 +1,39 @@ +import { OTLPTraceExporter as OTLPTraceExporterGrpc } from '@opentelemetry/exporter-trace-otlp-grpc'; import { OTLPTraceExporter as OTLPTraceExporterHttp } from '@opentelemetry/exporter-trace-otlp-http'; +import { OTLPTraceExporter as OTLPTraceExporterProto } from '@opentelemetry/exporter-trace-otlp-proto'; import { NodeSDK, resources, tracing } from '@opentelemetry/sdk-node'; import { Logger } from './log'; const logger = new Logger('tracing'); -export function initTracing(endpoint: string, samplePercentage = 1.0) { - const traceExporter = new OTLPTraceExporterHttp({ - url: endpoint.includes('/v1/traces') ? endpoint : `${endpoint}/v1/traces`, - }); +interface TracingConfig { + exporter?: 'grpc' | 'http' | 'proto'; + endpoint: string; + samplePercentage?: number; + attributes?: Record; +} + +export function initTracing(config: TracingConfig) { + const { endpoint, samplePercentage = 1.0, attributes = {}, exporter = 'http' } = config; + let traceExporter; + if (exporter === 'grpc') { + traceExporter = new OTLPTraceExporterGrpc({ + url: endpoint, + }); + } else if (exporter === 'proto') { + traceExporter = new OTLPTraceExporterProto({ + url: endpoint, + }); + } else { + traceExporter = new OTLPTraceExporterHttp({ + url: endpoint.includes('/v1/traces') ? endpoint : `${endpoint}/v1/traces`, + }); + } const sdk = new NodeSDK({ resource: resources.resourceFromAttributes({ 'service.name': 'hydrojudge', 'service.version': require('../package.json').version, + ...attributes, }), traceExporter, sampler: new tracing.TraceIdRatioBasedSampler(samplePercentage),