Skip to content

Commit

Permalink
feat(telemetry): use endowed console
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Jan 8, 2025
1 parent d1af13d commit ff30edd
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 15 deletions.
2 changes: 2 additions & 0 deletions packages/telemetry/src/context-aware-slog-file.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-env node */
/* global globalThis */

import { makeFsStreamWriter } from '@agoric/internal/src/node/fs-stream.js';
import { makeContextualSlogProcessor } from './context-aware-slog.js';
Expand All @@ -9,6 +10,7 @@ import { serializeSlogObj } from './serialize-slog-obj.js';
*/
export const makeSlogSender = async options => {
const { CHAIN_ID, CONTEXTUAL_SLOGFILE } = options.env || {};
const { console = globalThis.console } = options;
if (!CONTEXTUAL_SLOGFILE)
return console.warn(
'Ignoring invocation of slogger "context-aware-slog-file" without the presence of "CONTEXTUAL_SLOGFILE"',
Expand Down
12 changes: 9 additions & 3 deletions packages/telemetry/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export * from './make-slog-sender.js';
* @typedef {MakeSlogSenderCommonOptions & Record<string, unknown>} MakeSlogSenderOptions
* @typedef {object} MakeSlogSenderCommonOptions
* @property {Record<string, string | undefined>} [env]
* @property {Pick<Console, 'debug' | 'log' | 'info' | 'warn' | 'error'>} [console]
* @property {string} [stateDir]
* @property {string} [serviceName]
*/
Expand All @@ -28,11 +29,16 @@ export * from './make-slog-sender.js';
* @param {SlogSender} [slogSender]
* @param {object} [options]
* @param {Record<string, string | undefined>} [options.env]
* @param {(...args: any[]) => void} [options.log]
* @param {MakeSlogSenderCommonOptions['console']} [options.console]
* @param {(...args) => void} [options.log]
*/
export const tryFlushSlogSender = async (
slogSender,
{ env = {}, log } = {},
{
env = {},
console = globalThis.console,
log = (...args) => console.warn(...args),
} = {},
) => {
await Promise.resolve(slogSender?.forceFlush?.()).catch(err => {
log?.('Failed to flush slog sender', err);
Expand Down Expand Up @@ -81,7 +87,7 @@ export const getResourceAttributes = ({

/**
* @typedef {object} Powers
* @property {{ warn: Console['warn'] }} console
* @property {MakeSlogSenderCommonOptions['console']} console
* @property {NodeJS.ProcessEnv} env
* @property {import('@opentelemetry/sdk-metrics').View[]} views
* @property {string} [serviceName]
Expand Down
8 changes: 7 additions & 1 deletion packages/telemetry/src/make-slog-sender.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global globalThis */
import path from 'path';
import tmp from 'tmp';
import { PromiseAllOrErrors } from '@agoric/internal';
Expand All @@ -22,7 +23,12 @@ const filterTruthy = arr => /** @type {any[]} */ (arr.filter(Boolean));
* @type {import('./index.js').MakeSlogSender}
*/
export const makeSlogSender = async (opts = {}) => {
const { env = {}, stateDir: stateDirOption, ...otherOpts } = opts;
const {
env = {},
console = globalThis.console,
stateDir: stateDirOption,
...otherOpts
} = opts;
const {
SLOGSENDER = DEFAULT_SLOGSENDER_MODULE,
SLOGSENDER_AGENT = DEFAULT_SLOGSENDER_AGENT,
Expand Down
2 changes: 2 additions & 0 deletions packages/telemetry/src/otel-and-flight-recorder.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global globalThis */
import { NonNullish } from '@agoric/internal';
import { makeSlogSender as makeSlogSenderFromEnv } from './make-slog-sender.js';

Expand All @@ -6,6 +7,7 @@ import { makeSlogSender as makeSlogSenderFromEnv } from './make-slog-sender.js';
*/
export const makeSlogSender = async opts => {
const { SLOGFILE: _1, SLOGSENDER: _2, ...otherEnv } = opts.env || {};
const { console = globalThis.console } = opts || {};

console.warn(
'Deprecated slog sender, please use SLOGSENDER=@agoric/telemetry/src/flight-recorder.js,@agoric/telemetry/src/otel-trace.js',
Expand Down
10 changes: 9 additions & 1 deletion packages/telemetry/src/otel-context-aware-slog.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-env node */
/* global globalThis */
import { logs, SeverityNumber } from '@opentelemetry/api-logs';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { Resource } from '@opentelemetry/resources';
Expand All @@ -16,8 +17,13 @@ const FILE_ENCODING = 'utf8';

/**
* @param {string} filePath
* @param {object} [powers]
* @param {import('./index.js').MakeSlogSenderCommonOptions['console']} [powers.console]
*/
export const getContextFilePersistenceUtils = filePath => {
export const getContextFilePersistenceUtils = (
filePath,
{ console = globalThis.console } = {},
) => {
console.warn(`Using file ${filePath} for slogger context`);

return {
Expand Down Expand Up @@ -51,6 +57,7 @@ export const getContextFilePersistenceUtils = filePath => {
*/
export const makeSlogSender = async options => {
const { CHAIN_ID, OTEL_EXPORTER_OTLP_ENDPOINT } = options.env || {};
const { console = globalThis.console } = options;
if (!(OTEL_EXPORTER_OTLP_ENDPOINT && options.stateDir))
return console.error(
'Ignoring invocation of slogger "context-aware-slog" without the presence of "OTEL_EXPORTER_OTLP_ENDPOINT" and "stateDir"',
Expand All @@ -71,6 +78,7 @@ export const makeSlogSender = async options => {
const persistenceUtils = getContextFilePersistenceUtils(
process.env.SLOG_CONTEXT_FILE_PATH ||
`${options.stateDir}/${DEFAULT_CONTEXT_FILE}`,
{ console: options.console },
);

const contextualSlogProcessor = makeContextualSlogProcessor(
Expand Down
12 changes: 7 additions & 5 deletions packages/telemetry/src/otel-trace.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* globals process */
/* globals process globalThis */
import {
BasicTracerProvider,
BatchSpanProcessor,
Expand All @@ -16,11 +16,10 @@ export const SPAN_MAX_QUEUE_SIZE = 100_000;
export const SPAN_EXPORT_DELAY_MS = 1_000;

/**
* @param {object} opts
* @param {Record<string, string>} opts.env
* @param {import('./index.js').MakeSlogSenderCommonOptions} opts
*/
export const makeOtelTracingProvider = opts => {
const { env = process.env } = opts || {};
const { env = process.env, console = globalThis.console } = opts || {};

const { OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT } =
env;
Expand All @@ -45,14 +44,17 @@ export const makeOtelTracingProvider = opts => {
return provider;
};

/**
* @param {import('./index.js').MakeSlogSenderOptions & { version?: string }} opts
*/
export const makeSlogSender = async opts => {
const tracingProvider =
makeOtelTracingProvider(opts) || new BasicTracerProvider();

tracingProvider.register();
const tracer = tracingProvider.getTracer('slog-trace', opts.version);

const { slogSender, finish } = makeSlogToOtelKit(tracer);
const { slogSender, finish } = makeSlogToOtelKit(tracer, undefined, opts);

// Cleanly shutdown if possible.
const { registerShutdown } = makeShutdown();
Expand Down
5 changes: 4 additions & 1 deletion packages/telemetry/src/slog-to-otel.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global globalThis */
import otel, { SpanStatusCode } from '@opentelemetry/api';

import { Fail, q } from '@endo/errors';
Expand Down Expand Up @@ -78,8 +79,10 @@ export const floatSecondsToHiRes = sFloat => {
/**
* @param {import('@opentelemetry/api').Tracer} tracer
* @param {Record<string, any>} [overrideAttrs]
* @param {import('./index.js').MakeSlogSenderOptions} [powers]
*/
export const makeSlogToOtelKit = (tracer, overrideAttrs = {}) => {
export const makeSlogToOtelKit = (tracer, overrideAttrs = {}, powers = {}) => {
const { console = globalThis.console } = powers;
let now;
let nowFloat;
/** @type {Record<string, any>} */
Expand Down
16 changes: 12 additions & 4 deletions packages/telemetry/test/import.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* global setTimeout */
import { info } from 'console';

Check failure on line 2 in packages/telemetry/test/import.test.js

View workflow job for this annotation

GitHub Actions / lint-primary

'info' is defined but never used. Allowed unused vars must match /^_/u
import { test } from './prepare-test-env-ava.js';

import { getTelemetryProviders } from '../src/index.js';
Expand All @@ -8,10 +9,17 @@ const sleep = timeoutMs =>

test('get telemetry providers', async t => {
const logged = [];
const mockMethod =
level =>
(...args) => {
logged.push([level, ...args]);
};
const mockConsole = {
warn: (...args) => {
logged.push(args);
},
debug: mockMethod('debug'),
log: mockMethod('log'),
info: mockMethod('info'),
warn: mockMethod('warn'),
error: mockMethod('error'),
};
const providers = getTelemetryProviders({ console: mockConsole, env: {} });
t.is(providers.metricsProvider, undefined);
Expand All @@ -31,6 +39,6 @@ test('get telemetry providers', async t => {
t.deepEqual(logged, []);
await sleep(250);
t.deepEqual(logged, [
['Prometheus scrape endpoint: http://0.0.0.0:9393/metrics'],
['warn', 'Prometheus scrape endpoint: http://0.0.0.0:9393/metrics'],
]);
});

0 comments on commit ff30edd

Please sign in to comment.