feat(users/Profpatsch): Implement initial otel-dbus proxy

For simplicity’s sake this puts everything into the
alacritty-change-color-scheme script for now.

This implements a simple dbus-opentelemetry proxy adapter, which
allows services to record otel traces without having to depend on the
quite complex otel libraries. Instead, they just send their traces to
the dbus tracing interface, and the service that binds against that
interface forwards the spans to the OTLP collector.

First you create a new Tracer for your service via the `TracerFactory`
interface:

```
> busctl --user call \
    de.profpatsch.otel.Tracer \
    /de/profpatsch/otel/TracerFactory \
    de.profpatsch.otel.TracerFactory CreateTracer \
    s hello
s "/de/profpatsch/otel/tracers/hello"
```

(this corresponds to setting up a tracer with properties in OTEL)

Then, you can use the returned object path to call the `Tracer`
interface proper:

```
< busctl --user call \
    de.profpatsch.otel.Tracer \
    /de/profpatsch/otel/tracers/hello \
    de.profpatsch.otel.Tracer \
    StartSpan \
    s '{"spanId": "111", "name": "111"}'
```

This will create the spans. You can also set their timestamps on the
sending side via `startTime`/`endTime`, but make sure it’s a hrtime
tuple.

Prefer batching multiple spans vie the `BatchSpans` call.

Change-Id: Ie6cfdcb0dc3e2398316a2c1763bc72c1118168b0
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12885
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
Reviewed-by: benjaminedwardwebb <benjaminedwardwebb@gmail.com>
This commit is contained in:
Profpatsch 2024-12-09 21:10:01 +01:00
parent 821ff7ffe4
commit 4eeac3cb1d
3 changed files with 754 additions and 66 deletions

View file

@ -1,7 +1,22 @@
//@ts-check
// Step 3: Create the script // Step 3: Create the script
const dbus = require('dbus-native'); const dbus = require('dbus-native');
const fs = require('fs'); const fs = require('fs');
const assert = require('assert'); const assert = require('assert');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const {
BasicTracerProvider,
BatchSpanProcessor,
ConsoleSpanExporter,
SimpleSpanProcessor,
} = require('@opentelemetry/sdk-trace-base');
const opentelemetry = require('@opentelemetry/api');
const { hrTime } = require('@opentelemetry/core');
const { AsyncHooksContextManager } = require('@opentelemetry/context-async-hooks');
const { EventEmitter } = require('stream');
const { setTimeout } = require('node:timers/promises');
const { promisify } = require('util');
// NB: this code is like 80% copilot generated, and seriously missing error handling. // NB: this code is like 80% copilot generated, and seriously missing error handling.
// It might break at any time, but for now it seems to work lol. // It might break at any time, but for now it seems to work lol.
@ -21,8 +36,148 @@ console.log(`Dark theme: ${darkTheme}`);
console.log(`Light theme: ${lightTheme}`); console.log(`Light theme: ${lightTheme}`);
// Connect to the user session bus // Connect to the user session bus
/** @type any */
const bus = dbus.sessionBus(); const bus = dbus.sessionBus();
opentelemetry.diag.setLogger({ ...console, verbose: console.log });
const exporter = new OTLPTraceExporter();
const consoleExporter = new ConsoleSpanExporter();
const provider = new BasicTracerProvider({
//@ts-ignore
resource: {
attributes: {
'service.name': 'alacritty-change-color-scheme',
// 'service.namespace': 'default',
// 'service.instance.id': 'alacritty-change-color-scheme-01',
// 'service.version': '0.0.1',
},
},
spanProcessors: [
// new BatchSpanProcessor(exporter, {
// maxQueueSize: 100,
// scheduledDelayMillis: 5000,
// }),
new SimpleSpanProcessor(exporter),
new SimpleSpanProcessor(consoleExporter),
],
});
provider.register({
contextManager: new AsyncHooksContextManager().enable(),
});
const dbusSpanEmitter = new EventEmitter();
dbusSpanEmitter.on('new-root-span', onNewRootSpan);
/** @typedef {{spanId: string, name: string, parentId?: string, startTime?: opentelemetry.TimeInput, attributes?: opentelemetry.Attributes}} StartSpan */
/** @typedef {{spanId: string, endTime?: opentelemetry.TimeInput}} EndSpan */
/** @param {opentelemetry.Tracer} tracer,
* @param {StartSpan} spanData */
function emitNewRootSpanEvent(tracer, spanData) {
dbusSpanEmitter.emit('new-root-span', tracer, spanData);
}
/** @param {StartSpan} childSpanData */
function emitNewChildSpanEvent(parentSpanId, childSpanData) {
dbusSpanEmitter.emit(`new-child-span-for/${parentSpanId}`, childSpanData);
}
/** @param {EndSpan} endSpanData */
function emitEndSpanEvent(endSpanData) {
dbusSpanEmitter.emit(`end-span-for/${endSpanData.spanId}`, endSpanData);
}
/** @param {opentelemetry.Tracer} tracer
* @param {StartSpan} spanData */
function onNewRootSpan(tracer, spanData) {
console.log(`New span: ${spanData.spanId}`);
setupActiveSpan(tracer, spanData);
}
/** @param {opentelemetry.Tracer} tracer
* @param {StartSpan} spanData */
function setupActiveSpan(tracer, spanData) {
const SPAN_TIMEOUT = 1_000_000; // 1000 seconds
const SPAN_TIMEOUT_SHORT = 10_000; // 10 seconds
if (typeof spanData.startTime === 'number') {
console.warn(
'startTime is a number, not a hrTime tuple. This would use perfomance.now() in the wrong context, so we are ignoring it.',
);
spanData.startTime = undefined;
}
tracer.startActiveSpan(
spanData.name,
{ startTime: spanData.startTime, attributes: spanData.attributes },
span => {
let activeContext = opentelemetry.context.active();
/** @param {{spanId: string, name: string}} childSpanData */
function onNewChildSpan(childSpanData) {
opentelemetry.context.with(activeContext, () => {
console.log(`New child span: ${childSpanData.spanId}`);
setupActiveSpan(tracer, childSpanData);
});
}
dbusSpanEmitter.on(`new-child-span-for/${spanData.spanId}`, onNewChildSpan);
const removeTimeoutOnEnd = new AbortController();
/** @param {{endTime?: opentelemetry.TimeInput}} endSpanData */
function onEndSpan(endSpanData) {
opentelemetry.context.with(activeContext, () => {
console.log(`End span: ${spanData.spanId}`);
if (typeof endSpanData.endTime === 'number') {
console.warn(
'endTime is a number, not a hrTime tuple. This would use perfomance.now() in the wrong context, so we are ignoring it.',
);
endSpanData.endTime = undefined;
}
span.end(endSpanData.endTime);
// we dont remove the child span listener here, because in theory child spans dont have to be inside parent spans.
// However, we only want to keep the child span listener around for a little more, so lets set a shorter timeout here
setTimeout(SPAN_TIMEOUT_SHORT).then(() => {
dbusSpanEmitter.off(`new-child-span-for/${spanData.spanId}`, onNewChildSpan);
});
// remove the general long timeout belove
removeTimeoutOnEnd.abort();
});
}
dbusSpanEmitter.once(`end-span-for/${spanData.spanId}`, onEndSpan);
// don't keep spans contexts open forever if we never get a second message
// but we dont end the spans, just remove the listeners.
setTimeout(SPAN_TIMEOUT, undefined, { signal: removeTimeoutOnEnd.signal })
.then(() => {
console.warn(
`Timeout for span ${spanData.spanId}, removing all event listeners`,
);
dbusSpanEmitter.off(`new-child-span-for/${spanData.spanId}`, onNewChildSpan);
dbusSpanEmitter.off(`end-span-for/${spanData.spanId}`, onEndSpan);
})
.catch(err => {
if (err.name === 'AbortError') {
// console.log(`Timeout for span ${spanData.spanId} was aborted`);
} else {
throw err;
}
});
},
);
}
// tracer.startActiveSpan('222', span => {
// span.setAttribute('blabla', 'alacritty-change-color-scheme');
// tracer.startActiveSpan('333', span => {
// span.setAttribute('foo', 'bar');
// span.end();
// });
// // span.setAttribute('service.name', 'alacritty-change-color-scheme');
// // span.setAttribute('service.version', '0.0.1');
// span.end();
// });
// set XDG_CONFIG_HOME if it's not set // set XDG_CONFIG_HOME if it's not set
if (!process.env.XDG_CONFIG_HOME) { if (!process.env.XDG_CONFIG_HOME) {
process.env.XDG_CONFIG_HOME = process.env.HOME + '/.config'; process.env.XDG_CONFIG_HOME = process.env.HOME + '/.config';
@ -35,8 +190,12 @@ function getThemePathSync(theme) {
return absolutePath; return absolutePath;
} }
// write new color scheme /** write new color scheme
function writeAlacrittyColorConfig(cs, theme) { *
* @param {'prefer-dark' | 'prefer-light'} cs
*/
function writeAlacrittyColorConfig(cs) {
const theme = cs === 'prefer-dark' ? darkTheme : lightTheme;
console.log(`Writing color scheme ${cs} with theme ${theme}`); console.log(`Writing color scheme ${cs} with theme ${theme}`);
fs.writeFileSync( fs.writeFileSync(
process.env.XDG_CONFIG_HOME + '/alacritty/alacritty-colors-autogen.toml', process.env.XDG_CONFIG_HOME + '/alacritty/alacritty-colors-autogen.toml',
@ -46,35 +205,41 @@ general.import = ["${theme}"]`,
); );
} }
// get the current value of the color scheme from dbus /** get the current value of the color scheme from dbus
function getColorScheme() { *
return new Promise((resolve, reject) => { * @returns {Promise<'prefer-dark' | 'prefer-light'>}
bus */
.getService('org.freedesktop.portal.Desktop') async function getColorScheme() {
.getInterface( let service = bus.getService('org.freedesktop.portal.Desktop');
let iface = await promisifyMethodAnnotate(
service,
service.getInterface,
'Error getting interface',
'/org/freedesktop/portal/desktop', '/org/freedesktop/portal/desktop',
'org.freedesktop.portal.Settings', 'org.freedesktop.portal.Settings',
(err, iface) => { );
if (err) {
reject(`error getting interface: ${err}`);
return;
}
iface.ReadOne( const [_, [value]] = await promisifyMethodAnnotate(
iface,
iface.ReadOne,
'Error reading color scheme',
'org.gnome.desktop.interface', 'org.gnome.desktop.interface',
'color-scheme', 'color-scheme',
(err, [_, [value]]) => { );
if (err) { assert(value === 'prefer-dark' || value === 'prefer-light');
reject(err); return value;
return; }
}
resolve(value); /** promisify an object method and annotate any errors that get thrown
}, * @template {Function} A
); * @param {object} obj
}, * @param {A} method
); * @param {string} msg
}); * @param {...any} args
* @returns {Promise<ReturnType<A>>}
*/
function promisifyMethodAnnotate(obj, method, msg, ...args) {
return promisify(method.bind(obj))(...args).catch(annotateErr(msg));
} }
/** write respective alacritty config if the colorscheme changes. /** write respective alacritty config if the colorscheme changes.
@ -90,40 +255,33 @@ function writeAlacrittyColorConfigIfDifferent(cs) {
previous = cs; previous = cs;
console.log(`Color scheme changed to ${cs}`); console.log(`Color scheme changed to ${cs}`);
writeAlacrittyColorConfig(cs, cs === 'prefer-dark' ? darkTheme : lightTheme); writeAlacrittyColorConfig(cs);
} }
/** Listen on the freedesktop SettingChanged dbus interface for the color-scheme setting to change. */ /** Listen on the freedesktop SettingChanged dbus interface for the color-scheme setting to change. */
function listenForColorschemeChange() { async function listenForColorschemeChange() {
return new Promise((resolve, reject) => { const service = bus.getService('org.freedesktop.portal.Desktop');
bus
.getService('org.freedesktop.portal.Desktop') const iface = await promisifyMethodAnnotate(
.getInterface( service,
service.getInterface,
'Error getting interface',
'/org/freedesktop/portal/desktop', '/org/freedesktop/portal/desktop',
'org.freedesktop.portal.Settings', 'org.freedesktop.portal.Settings',
(err, iface) => { );
if (err) {
reject(`error getting interface: ${err}`);
}
// Listen for SettingChanged signals // Listen for SettingChanged signals
iface.on('SettingChanged', (interfaceName, key, [_, [newValue]]) => { iface.on('SettingChanged', (interfaceName, key, [_, [newValue]]) => {
if ( if (interfaceName === 'org.gnome.desktop.interface' && key == 'color-scheme') {
interfaceName === 'org.gnome.desktop.interface' &&
key == 'color-scheme'
) {
writeAlacrittyColorConfigIfDifferent(newValue); writeAlacrittyColorConfigIfDifferent(newValue);
} }
}); });
console.log('Listening for color scheme changes...'); console.log('Listening for color scheme changes...');
},
);
});
} }
/** Create a dbus service that binds against the interface de.profpatsch.alacritty.ColorScheme and implements the method SetColorScheme */ /** Create a dbus service that binds against the interface de.profpatsch.alacritty.ColorScheme and implements the method SetColorScheme */
function exportColorSchemeDbusInterface() { async function exportColorSchemeDbusInterface() {
console.log('Exporting color scheme interface de.profpatsch.alacritty.ColorScheme'); console.log('Exporting color scheme interface de.profpatsch.alacritty.ColorScheme');
const ifaceName = 'de.profpatsch.alacritty.ColorScheme'; const ifaceName = 'de.profpatsch.alacritty.ColorScheme';
const iface = { const iface = {
@ -141,18 +299,18 @@ function exportColorSchemeDbusInterface() {
}; };
try { try {
bus.requestName(ifaceName, 0, (err, retCode) => { const retCode = await promisifyMethodAnnotate(
if (err) { bus,
console.error( bus.requestName,
'Error requesting name for interface de.profpatsch.alacritty.ColorScheme', 'Error requesting name for interface de.profpatsch.alacritty.ColorScheme',
ifaceName,
0,
); );
console.error(err);
}
console.log( console.log(
`Request name returned ${retCode} for interface de.profpatsch.alacritty.ColorScheme`, `Request name returned ${retCode} for interface de.profpatsch.alacritty.ColorScheme`,
); );
});
bus.exportInterface(ifaceImpl, '/de/profpatsch/alacritty/ColorScheme', iface); bus.exportInterface(ifaceImpl, '/de/profpatsch/alacritty/ColorScheme', iface);
bus.exportInterface(ifaceImpl, '/de/profpatsch/alacritty/ColorScheme2', iface);
console.log('Exported interface de.profpatsch.alacritty.ColorScheme'); console.log('Exported interface de.profpatsch.alacritty.ColorScheme');
} catch (err) { } catch (err) {
console.log('Error exporting interface de.profpatsch.alacritty.ColorScheme'); console.log('Error exporting interface de.profpatsch.alacritty.ColorScheme');
@ -160,10 +318,239 @@ function exportColorSchemeDbusInterface() {
} }
} }
/** Annotate an error as a promise .catch handler (rethrows the annotated error)
* @param {string} msg
* @returns {function(Error): void}
*/
function annotateErr(msg) {
return err => {
msg = err.message ? `${msg}: ${err.message}` : msg;
err.message = msg;
throw err;
};
}
/** @type any */
const bus2 = dbus.sessionBus();
async function exportOtelInterface() {
console.log('Exporting OpenTelemetry interface');
try {
const retCode = await promisifyMethodAnnotate(
bus2,
bus2.requestName,
'Error requesting name for interface de.profpatsch.otel.Tracer',
'de.profpatsch.otel.Tracer',
0,
);
console.log(
`Request name returned ${retCode} for interface de.profpatsch.otel.Tracer`,
);
const traceIface = {
name: 'de.profpatsch.otel.Tracer',
methods: {
// These both just take a json string as input
StartSpan: ['s', ''],
EndSpan: ['s', ''],
// An array of [(isStartSpan: bool, span: Span)]
// So that you dont have to call dbus for every span
BatchSpans: ['a(bs)', ''],
},
};
/** @type {(arg: {tracer: opentelemetry.Tracer, tracerName: string}) => {StartSpan: (input: string) => void, EndSpan: (input: string) => void, BatchSpans: (input: [boolean, string][]) => void }} */
const traceImpl = tracer => ({
StartSpan: function (input) {
// TODO: actually verify json input
/** @type {StartSpan} */
const spanArgs = JSON.parse(input);
if (spanArgs.parentId === undefined) {
console.log(
`Tracing root span ${spanArgs.name} with tracer ${tracer.tracerName}`,
);
emitNewRootSpanEvent(tracer.tracer, spanArgs);
} else {
console.log(
`Tracing child span ${spanArgs.name} with tracer ${tracer.tracerName}`,
);
emitNewChildSpanEvent(spanArgs.parentId, spanArgs);
}
},
EndSpan: function (input) {
// TODO: actually verify json input
/** @type {EndSpan} */
const spanArgs = JSON.parse(input);
console.log(`Ending span ${spanArgs.spanId} with tracer ${tracer.tracerName}`);
emitEndSpanEvent(spanArgs);
},
BatchSpans: function (input) {
// lol
for (const [isStartSpan, span] of input) {
if (isStartSpan) {
traceImpl(tracer).StartSpan(span);
} else {
traceImpl(tracer).EndSpan(span);
}
}
},
});
bus2.exportInterface(
{
CreateTracer: function (tracerName) {
console.log(`Creating tracer with name ${tracerName}`);
const tracer = opentelemetry.trace.getTracer(tracerName, '0.0.1');
bus2.exportInterface(
traceImpl({ tracer, tracerName }),
`/de/profpatsch/otel/tracers/${tracerName}`,
traceIface,
);
return `/de/profpatsch/otel/tracers/${tracerName}`;
},
},
'/de/profpatsch/otel/TracerFactory',
{
name: 'de.profpatsch.otel.TracerFactory',
methods: {
CreateTracer: ['s', 's'],
},
},
);
console.log('Exported interface de.profpatsch.otel.TracerFactory');
} catch (err) {
console.log('Error exporting interface de.profpatsch.alacritty.ColorScheme');
console.error(err);
}
}
/** Returns the callsite of the function calling `getParentCallsite`, if any. */
async function getParentCallsite() {
const getCallsites = (await import('callsites')).default;
const cs = getCallsites();
return cs[2] ?? cs[1] ?? null;
}
/** Calls the tracer dbus interface, sets up a tracer
*
* @param {string} tracerName The name of the tracer to set up
* @returns {Promise<{
* StartSpan: (spanData: StartSpan) => Promise<void>,
* EndSpan: (spanData: EndSpan) => Promise<void>,
* BatchSpans: (spans: ([true, StartSpan] | [false, EndSpan])[]) => Promise<void>
* }>}
*/
async function setupTracer(tracerName) {
const parentCallsite = await getParentCallsite();
console.log(`Setting up tracer ${tracerName} from ${parentCallsite?.getFileName()}`);
const service = bus2.getService('de.profpatsch.otel.Tracer');
const iface = await promisifyMethodAnnotate(
service,
service.getInterface,
'Error getting interface',
'/de/profpatsch/otel/TracerFactory',
'de.profpatsch.otel.TracerFactory',
);
const path = await promisifyMethodAnnotate(
iface,
iface.CreateTracer,
'Error creating tracer',
tracerName,
);
const tracerIface = await promisifyMethodAnnotate(
service,
service.getInterface,
'Error getting interface',
path,
'de.profpatsch.otel.Tracer',
);
function StartSpan(spanData) {
return promisifyMethodAnnotate(
tracerIface,
tracerIface.StartSpan,
'Error starting span',
JSON.stringify(spanData),
);
}
function EndSpan(spanData) {
return promisifyMethodAnnotate(
tracerIface,
tracerIface.EndSpan,
'Error ending span',
JSON.stringify(spanData),
);
}
function BatchSpans(spans) {
return promisifyMethodAnnotate(
tracerIface,
tracerIface.BatchSpans,
'Error batching spans',
spans.map(([isStartSpan, span]) => [isStartSpan, JSON.stringify(span)]),
);
}
return {
StartSpan,
EndSpan,
BatchSpans,
};
}
async function main() { async function main() {
await exportOtelInterface();
const tracer = await setupTracer('hello');
await tracer.StartSpan({
name: 'hello',
spanId: 'hello',
startTime: hrTime(),
attributes: {
foo: 'bar',
},
});
await tracer.StartSpan({
name: 'world',
spanId: 'world',
parentId: 'hello',
attributes: {
bar: 'baz',
},
});
await tracer.EndSpan({
spanId: 'world',
endTime: hrTime(),
});
await tracer.EndSpan({
spanId: 'hello',
endTime: hrTime(),
});
const t = performance.now();
await tracer.BatchSpans([
[
true,
{
name: 'batchy',
spanId: 'batchy',
startTime: t,
attributes: { foo: 'bar' },
},
],
[
true,
{
name: 'worldy',
spanId: 'worldy',
parentId: 'batchy',
startTime: t + 100,
attributes: { bar: 'baz' },
},
],
[false, { spanId: 'worldy', endTime: t + 500 }],
[false, { spanId: 'batchy', endTime: t + 1000 }],
]);
// TODO: proper error handling, through proper callback promises for dbus function. // TODO: proper error handling, through proper callback promises for dbus function.
exportColorSchemeDbusInterface(); await exportColorSchemeDbusInterface();
// get the current color scheme // get the current color scheme
const currentColorScheme = await getColorScheme(); const currentColorScheme = await getColorScheme();

View file

@ -9,7 +9,267 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/context-async-hooks": "^1.29.0",
"@opentelemetry/core": "^1.29.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.56.0",
"@opentelemetry/sdk-trace-base": "^1.29.0",
"dbus-native": "^0.4.0" "dbus-native": "^0.4.0"
},
"bin": {
"alacritty-change-color-scheme": "alacritty-change-color-scheme.js"
}
},
"node_modules/@opentelemetry/api": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/@opentelemetry/api-logs": {
"version": "0.56.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.56.0.tgz",
"integrity": "sha512-Wr39+94UNNG3Ei9nv3pHd4AJ63gq5nSemMRpCd8fPwDL9rN3vK26lzxfH27mw16XzOSO+TpyQwBAMaLxaPWG0g==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/api": "^1.3.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@opentelemetry/context-async-hooks": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.29.0.tgz",
"integrity": "sha512-TKT91jcFXgHyIDF1lgJF3BHGIakn6x0Xp7Tq3zoS3TMPzT9IlP0xEavWP8C1zGjU9UmZP2VR1tJhW9Az1A3w8Q==",
"license": "Apache-2.0",
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/core": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.29.0.tgz",
"integrity": "sha512-gmT7vAreXl0DTHD2rVZcw3+l2g84+5XiHIqdBUxXbExymPCvSsGOpiwMmn8nkiJur28STV31wnhIDrzWDPzjfA==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/semantic-conventions": "1.28.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/exporter-trace-otlp-http": {
"version": "0.56.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.56.0.tgz",
"integrity": "sha512-vqVuJvcwameA0r0cNrRzrZqPLB0otS+95g0XkZdiKOXUo81wYdY6r4kyrwz4nSChqTBEFm0lqi/H2OWGboOa6g==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "1.29.0",
"@opentelemetry/otlp-exporter-base": "0.56.0",
"@opentelemetry/otlp-transformer": "0.56.0",
"@opentelemetry/resources": "1.29.0",
"@opentelemetry/sdk-trace-base": "1.29.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/otlp-exporter-base": {
"version": "0.56.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.56.0.tgz",
"integrity": "sha512-eURvv0fcmBE+KE1McUeRo+u0n18ZnUeSc7lDlW/dzlqFYasEbsztTK4v0Qf8C4vEY+aMTjPKUxBG0NX2Te3Pmw==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "1.29.0",
"@opentelemetry/otlp-transformer": "0.56.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/otlp-transformer": {
"version": "0.56.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.56.0.tgz",
"integrity": "sha512-kVkH/W2W7EpgWWpyU5VnnjIdSD7Y7FljQYObAQSKdRcejiwMj2glypZtUdfq1LTJcv4ht0jyTrw1D3CCxssNtQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/api-logs": "0.56.0",
"@opentelemetry/core": "1.29.0",
"@opentelemetry/resources": "1.29.0",
"@opentelemetry/sdk-logs": "0.56.0",
"@opentelemetry/sdk-metrics": "1.29.0",
"@opentelemetry/sdk-trace-base": "1.29.0",
"protobufjs": "^7.3.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
}
},
"node_modules/@opentelemetry/resources": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.29.0.tgz",
"integrity": "sha512-s7mLXuHZE7RQr1wwweGcaRp3Q4UJJ0wazeGlc/N5/XSe6UyXfsh1UQGMADYeg7YwD+cEdMtU1yJAUXdnFzYzyQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "1.29.0",
"@opentelemetry/semantic-conventions": "1.28.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/sdk-logs": {
"version": "0.56.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.56.0.tgz",
"integrity": "sha512-OS0WPBJF++R/cSl+terUjQH5PebloidB1Jbbecgg2rnCmQbTST9xsRes23bLfDQVRvmegmHqDh884h0aRdJyLw==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/api-logs": "0.56.0",
"@opentelemetry/core": "1.29.0",
"@opentelemetry/resources": "1.29.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.4.0 <1.10.0"
}
},
"node_modules/@opentelemetry/sdk-metrics": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.29.0.tgz",
"integrity": "sha512-MkVtuzDjXZaUJSuJlHn6BSXjcQlMvHcsDV7LjY4P6AJeffMa4+kIGDjzsCf6DkAh6Vqlwag5EWEam3KZOX5Drw==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "1.29.0",
"@opentelemetry/resources": "1.29.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.3.0 <1.10.0"
}
},
"node_modules/@opentelemetry/sdk-trace-base": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.29.0.tgz",
"integrity": "sha512-hEOpAYLKXF3wGJpXOtWsxEtqBgde0SCv+w+jvr3/UusR4ll3QrENEGnSl1WDCyRrpqOQ5NCNOvZch9UFVa7MnQ==",
"license": "Apache-2.0",
"dependencies": {
"@opentelemetry/core": "1.29.0",
"@opentelemetry/resources": "1.29.0",
"@opentelemetry/semantic-conventions": "1.28.0"
},
"engines": {
"node": ">=14"
},
"peerDependencies": {
"@opentelemetry/api": ">=1.0.0 <1.10.0"
}
},
"node_modules/@opentelemetry/semantic-conventions": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz",
"integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==",
"license": "Apache-2.0",
"engines": {
"node": ">=14"
}
},
"node_modules/@protobufjs/aspromise": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/base64": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/eventemitter": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/fetch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
"license": "BSD-3-Clause",
"dependencies": {
"@protobufjs/aspromise": "^1.1.1",
"@protobufjs/inquire": "^1.1.0"
}
},
"node_modules/@protobufjs/float": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/path": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/pool": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
"license": "BSD-3-Clause"
},
"node_modules/@types/node": {
"version": "22.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz",
"integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
} }
}, },
"node_modules/abstract-socket": { "node_modules/abstract-socket": {
@ -152,6 +412,36 @@
"through": "~2.3" "through": "~2.3"
} }
}, },
"node_modules/protobufjs": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
"integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
"hasInstallScript": true,
"license": "BSD-3-Clause",
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/protobufjs/node_modules/long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==",
"license": "Apache-2.0"
},
"node_modules/put": { "node_modules/put": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz",
@ -215,6 +505,12 @@
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"license": "MIT"
},
"node_modules/wordwrap": { "node_modules/wordwrap": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",

View file

@ -10,6 +10,11 @@
"license": "ISC", "license": "ISC",
"description": "", "description": "",
"dependencies": { "dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/context-async-hooks": "^1.29.0",
"@opentelemetry/core": "^1.29.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.56.0",
"@opentelemetry/sdk-trace-base": "^1.29.0",
"dbus-native": "^0.4.0" "dbus-native": "^0.4.0"
} }
} }