Skip to content

Commit

Permalink
feat(diag-logger): introduce a new global level api.diag for internal…
Browse files Browse the repository at this point in the history
… diagnostic logging (#1880)

Co-authored-by: Daniel Dyla <[email protected]>
  • Loading branch information
MSNev and dyladan authored Feb 10, 2021
1 parent 000a8ac commit 1d682c2
Show file tree
Hide file tree
Showing 20 changed files with 1,287 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ package.json.lerna_backup
# VsCode configs
.vscode/

#Visual Studio
.vs/

#IDEA
.idea
*.iml
6 changes: 3 additions & 3 deletions benchmark/tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const benchmark = require('./benchmark');
const opentelemetry = require('../packages/opentelemetry-api');
const { BasicTracerProvider, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('../packages/opentelemetry-tracing');

const logger = new opentelemetry.NoopLogger();
const diagLogger = opentelemetry.createNoopDiagLogger();

const setups = [
{
Expand All @@ -13,7 +13,7 @@ const setups = [
},
{
name: 'BasicTracerProvider',
provider: new BasicTracerProvider({ logger })
provider: new BasicTracerProvider({ logger: diagLogger })
},
{
name: 'BasicTracerProvider with SimpleSpanProcessor',
Expand Down Expand Up @@ -63,7 +63,7 @@ for (const setup of setups) {
suite.run({ async: false });
}
function getProvider(processor) {
const provider = new BasicTracerProvider({ logger });
const provider = new BasicTracerProvider({ logger: diagLogger });
provider.addSpanProcessor(processor);
return provider;
}
Expand Down
7 changes: 5 additions & 2 deletions examples/collector-exporter-node/metrics.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
'use strict';

const { ConsoleLogger, LogLevel } = require('@opentelemetry/core');
const { DiagConsoleLogger, DiagLogLevel, diag } = require('@opentelemetry/api');
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
// const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector-grpc');
// const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector-proto');
const { MeterProvider } = require('@opentelemetry/metrics');

diag.setLogger(new DiagConsoleLogger());
diag.setLogLevel(DiagLogLevel.DEBUG);

const metricExporter = new CollectorMetricExporter({
serviceName: 'basic-metric-service',
// url: 'http://localhost:55681/v1/metrics',
logger: new ConsoleLogger(LogLevel.DEBUG),
logger: diag,
});

const meter = new MeterProvider({
Expand Down
5 changes: 3 additions & 2 deletions examples/collector-exporter-node/tracing.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
'use strict';

const opentelemetry = require('@opentelemetry/api');
// const { ConsoleLogger, LogLevel} = require('@opentelemetry/core');
const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector');
// const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-grpc');
// const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-proto');

// opentelemetry.diag.setLogger(new opentelemetry.DiagConsoleLogger());
// opentelemetry.diag.setLogLevel(opentelemetry.DiagLogLevel.DEBUG);

const exporter = new CollectorTraceExporter({
serviceName: 'basic-service',
// logger: new ConsoleLogger(LogLevel.DEBUG),
// headers: {
// foo: 'bar'
// },
Expand Down
4 changes: 2 additions & 2 deletions examples/metrics/metrics/observer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const { MeterProvider } = require('@opentelemetry/metrics');
const { ConsoleLogger, LogLevel } = require('@opentelemetry/core');
const { DiagConsoleLogger, DiagLogLevel, diagLogLevelFilter } = require('@opentelemetry/api');
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');

const exporter = new PrometheusExporter(
Expand Down Expand Up @@ -61,7 +61,7 @@ meter.createBatchObserver((observerBatchResult) => {
});
}, {
maxTimeoutUpdateMS: 500,
logger: new ConsoleLogger(LogLevel.DEBUG)
logger: diagLogLevelFilter(DiagLogLevel.DEBUG, new DiagConsoleLogger())
},
);

Expand Down
4 changes: 2 additions & 2 deletions examples/tracer-web/examples/metrics/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use strict';

const { ConsoleLogger, LogLevel } = require('@opentelemetry/core');
const { DiagConsoleLogger, DiagLogLevel, diagLogLevelFilter } = require('@opentelemetry/api');
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
const { MeterProvider } = require('@opentelemetry/metrics');

const metricExporter = new CollectorMetricExporter({
serviceName: 'basic-metric-service',
logger: new ConsoleLogger(LogLevel.DEBUG),
logger: diagLogLevelFilter(DiagLogLevel.DEBUG, new DiagConsoleLogger()),
});

let interval;
Expand Down
153 changes: 153 additions & 0 deletions packages/opentelemetry-api/src/api/diag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
DiagLogger,
DiagLogFunction,
createNoopDiagLogger,
diagLoggerFunctions,
} from '../diag/logger';
import { DiagLogLevel, createLogLevelDiagLogger } from '../diag/logLevel';
import {
API_BACKWARDS_COMPATIBILITY_VERSION,
GLOBAL_DIAG_LOGGER_API_KEY,
makeGetter,
_global,
} from './global-utils';

/** Internal simple Noop Diag API that returns a noop logger and does not allow any changes */
function noopDiagApi(): DiagAPI {
const noopApi = createNoopDiagLogger() as DiagAPI;

noopApi.getLogger = () => noopApi;
noopApi.setLogger = noopApi.getLogger;
noopApi.setLogLevel = () => {};

return noopApi;
}

/**
* Singleton object which represents the entry point to the OpenTelemetry internal
* diagnostic API
*/
export class DiagAPI implements DiagLogger {
/** Get the singleton instance of the DiagAPI API */
public static instance(): DiagAPI {
let theInst = null;
if (_global[GLOBAL_DIAG_LOGGER_API_KEY]) {
// Looks like a previous instance was set, so try and fetch it
theInst = _global[GLOBAL_DIAG_LOGGER_API_KEY]?.(
API_BACKWARDS_COMPATIBILITY_VERSION
) as DiagAPI;
}

if (!theInst) {
theInst = new DiagAPI();
_global[GLOBAL_DIAG_LOGGER_API_KEY] = makeGetter(
API_BACKWARDS_COMPATIBILITY_VERSION,
theInst,
noopDiagApi()
);
}

return theInst;
}

/**
* Private internal constructor
* @private
*/
private constructor() {
let _logLevel: DiagLogLevel = DiagLogLevel.INFO;
let _filteredLogger: DiagLogger | null;
let _logger: DiagLogger = createNoopDiagLogger();

function _logProxy(funcName: keyof DiagLogger): DiagLogFunction {
return function () {
const orgArguments = arguments as unknown;
const theLogger = _filteredLogger || _logger;
const theFunc = theLogger[funcName];
if (typeof theFunc === 'function') {
return theFunc.apply(
theLogger,
orgArguments as Parameters<DiagLogFunction>
);
}
};
}

// Using self local variable for minification purposes as 'this' cannot be minified
const self = this;

// DiagAPI specific functions

self.getLogger = (): DiagLogger => {
// Return itself if no existing logger is defined (defaults effectively to a Noop)
return _logger;
};

self.setLogger = (logger: DiagLogger): DiagLogger => {
const prevLogger = _logger;
if (prevLogger !== logger && logger !== self) {
// Simple special case to avoid any possible infinite recursion on the logging functions
_logger = logger || createNoopDiagLogger();
_filteredLogger = createLogLevelDiagLogger(_logLevel, _logger);
}

return prevLogger;
};

self.setLogLevel = (maxLogLevel: DiagLogLevel) => {
if (maxLogLevel !== _logLevel) {
_logLevel = maxLogLevel;
if (_logger) {
_filteredLogger = createLogLevelDiagLogger(maxLogLevel, _logger);
}
}
};

for (let i = 0; i < diagLoggerFunctions.length; i++) {
const name = diagLoggerFunctions[i];
self[name] = _logProxy(name);
}
}

/**
* Return the currently configured logger instance, if no logger has been configured
* it will return itself so any log level filtering will still be applied in this case.
*/
public getLogger!: () => DiagLogger;

/**
* Set the DiagLogger instance
* @param logger - The DiagLogger instance to set as the default logger
* @returns The previously registered DiagLogger
*/
public setLogger!: (logger: DiagLogger) => DiagLogger;

/** Set the default maximum diagnostic logging level */
public setLogLevel!: (maxLogLevel: DiagLogLevel) => void;

// DiagLogger implementation
public verbose!: DiagLogFunction;
public debug!: DiagLogFunction;
public info!: DiagLogFunction;
public warn!: DiagLogFunction;
public startupInfo!: DiagLogFunction;
public error!: DiagLogFunction;
public critical!: DiagLogFunction;
public terminal!: DiagLogFunction;
}
6 changes: 6 additions & 0 deletions packages/opentelemetry-api/src/api/global-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ContextManager } from '@opentelemetry/context-base';
import { TextMapPropagator } from '../context/propagation/TextMapPropagator';
import { TracerProvider } from '../trace/tracer_provider';
import { _globalThis } from '../platform';
import { DiagAPI } from '../api/diag';

export const GLOBAL_CONTEXT_MANAGER_API_KEY = Symbol.for(
'io.opentelemetry.js.api.context'
Expand All @@ -28,11 +29,16 @@ export const GLOBAL_PROPAGATION_API_KEY = Symbol.for(
);
export const GLOBAL_TRACE_API_KEY = Symbol.for('io.opentelemetry.js.api.trace');

export const GLOBAL_DIAG_LOGGER_API_KEY = Symbol.for(
'io.opentelemetry.js.api.diag'
);

type Get<T> = (version: number) => T;
type OtelGlobal = Partial<{
[GLOBAL_CONTEXT_MANAGER_API_KEY]: Get<ContextManager>;
[GLOBAL_PROPAGATION_API_KEY]: Get<TextMapPropagator>;
[GLOBAL_TRACE_API_KEY]: Get<TracerProvider>;
[GLOBAL_DIAG_LOGGER_API_KEY]: Get<DiagAPI>;
}>;

export const _global = _globalThis as OtelGlobal;
Expand Down
5 changes: 4 additions & 1 deletion packages/opentelemetry-api/src/common/Logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

export type LogFunction = (message: string, ...args: unknown[]) => void;

/** Defines a logger interface. */
/** Defines a logger interface.
* @deprecated This interface will be removed prior to v1.0, use the api.diag
* @see {@link DiagLogger} and {@link DiagAPI}
*/
export interface Logger {
error: LogFunction;
warn: LogFunction;
Expand Down
Loading

0 comments on commit 1d682c2

Please sign in to comment.