-
Notifications
You must be signed in to change notification settings - Fork 826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(diag-logger): replace logger with diag logger #1925
Conversation
* @param config The configuration to initialize the logger from | ||
* @param getDefaultLogger - A fallback callback to fetch the specific logger if no logger is configured | ||
*/ | ||
export function getDiagLoggerFromConfig( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Helper method for parsing the configuration to obtain the diagnostic logger.
Removes (most) of the need for boilerplate code to check and get the diagnostic logger.
Codecov Report
@@ Coverage Diff @@
## main #1925 +/- ##
==========================================
+ Coverage 92.45% 92.87% +0.42%
==========================================
Files 165 179 +14
Lines 5472 6332 +860
Branches 1157 1317 +160
==========================================
+ Hits 5059 5881 +822
- Misses 413 451 +38
|
error: errorStub, | ||
}); | ||
} as any); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is "safe" as the logging-error-handler only even calls error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's in a test anyway
@@ -35,7 +35,7 @@ export class JaegerExporter implements SpanExporter { | |||
|
|||
constructor(config: jaegerTypes.ExporterConfig) { | |||
const localConfig = Object.assign({}, config); | |||
this._logger = localConfig.logger || new api.NoopLogger(); | |||
this._diagLogger = getDiagLoggerFromConfig(localConfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will fallback to the api.diag rather than the previous NoopLogger, so while the default api.diag is a Noop Diag Logger, if it is set this would be a change in functionality.
@@ -54,7 +54,7 @@ export class PrometheusExporter implements MetricExporter { | |||
* @param callback Callback to be called after a server was started | |||
*/ | |||
constructor(config: ExporterConfig = {}, callback?: () => void) { | |||
this._logger = config.logger || new api.NoopLogger(); | |||
this._diagLogger = getDiagLoggerFromConfig(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will fallback to the api.diag rather than the previous NoopLogger, so while the default api.diag is a Noop Diag Logger, if it is set this would be a change in functionality.
@@ -42,8 +42,8 @@ export class ZipkinExporter implements SpanExporter { | |||
|
|||
constructor(config: zipkinTypes.ExporterConfig = {}) { | |||
const urlStr = config.url || ZipkinExporter.DEFAULT_URL; | |||
this._logger = config.logger || new api.NoopLogger(); | |||
this._send = prepareSend(this._logger, urlStr, config.headers); | |||
this._diagLogger = getDiagLoggerFromConfig(config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per other comments -- change in fallback behavior
const meterProvider = options.meterProvider || metrics.getMeterProvider(); | ||
const logger = | ||
options.logger || tracerWithLogger?.logger || new api.NoopLogger(); | ||
const diagLogger = getDiagLoggerFromConfig(options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per other comment -- change in fallback behavior.
@@ -55,7 +59,10 @@ export class Meter implements api.Meter { | |||
config: MeterConfig = {} | |||
) { | |||
const mergedConfig = merge({}, DEFAULT_CONFIG, config); | |||
this._logger = mergedConfig.logger || new ConsoleLogger(config.logLevel); | |||
this._diagLogger = getDiagLoggerFromConfig( | |||
mergedConfig, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike other usages of getDiagLoggerFromConfig(), the fallback logic here will still result in a console logger. And the logging level will still use the configured config.diagLogLevel
value as this occurs internally as part of the helper.
this.logger = | ||
mergedConfig.logger ?? new ConsoleLogger(mergedConfig.logLevel); | ||
this.diagLogger = getDiagLoggerFromConfig( | ||
mergedConfig, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment -- no change in fallback behavior or logging level.
packages/opentelemetry-core/src/common/logging-error-handler.ts
Outdated
Show resolved
Hide resolved
error: errorStub, | ||
}); | ||
} as any); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's in a test anyway
@@ -17,24 +17,24 @@ | |||
import { | |||
NOOP_TRACER, | |||
NoopTracerProvider, | |||
NoopLogger, | |||
createNoopDiagLogger, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this exported for any reason other than testing? If not, I would prefer it not be exported from the API package as it then becomes part of the API we have to support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is mostly for testing (as that is the most usage), to remove would require that all test usages would need to be refactored to not use it (which in most cases they shouldn't need at all). Do we want to do that as part of this PR?
It does raise the following questions
- Do we or should we have some sort of test "helpers" as for this a MockLogger that records all usages in memory would be useful?
- For all existing usages of
new NoopLogger()
what do we tell them for upgrading, as there may be at least one user that really want to sink all messages?
On the above, where should I add documentation on usage / upgrade notes for the release notes, so that we get people upgrading and using this in the prescribed way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Searching across all usages the only non-api and non-test usage is in opentelemetry-shim-opentracing\src\shim.ts which is currently
this._diagLogger = diagLogger || api.createNoopDiagLogger();
We could change this to following, but this would also be a function change -- does anyone know if this would be ok? As it would affect anyone using OpenTracing Tracers (as per the Readme)
this._diagLogger = diagLogger || diag;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm i'm not sure how that would affect the shim as i'm not that familiar with opentracing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like either should be safe as this logger is only used in the shim and not passed to opentracing itself.
Do we or should we have some sort of test "helpers" as for this a MockLogger that records all usages in memory would be useful?
I think something like that can be added later. For now I don't think it's something we need to focus on
For all existing usages of new NoopLogger() what do we tell them for upgrading, as there may be at least one user that really want to sink all messages?
if an end user is passing a NoopLogger into a component, they can just pass a disabled DiagLogger into it. Unless i've missed something?
On the above, where should I add documentation on usage / upgrade notes for the release notes, so that we get people upgrading and using this in the prescribed way?
in the README.md there is an upgrade guide. You can go ahead and add a new entry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like either should be safe as this logger is only used in the shim and not passed to opentracing itself.
I've left this alone for now.
if an end user is passing a NoopLogger into a component, they can just pass a disabled DiagLogger into it. Unless i've missed something?
Correct, you've not missed anything
in the README.md there is an upgrade guide. You can go ahead and add a new entry.
I've added a new 0.17 -> section to the readme.
packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this went into completely different direction than what we have discussed and agreed for.
The main idea was to be able to do something like this anywhere and always without worrying about whether the logger was set or not, and also to avoid parsing a logger everywhere.
api.logger.debug('....
api.logger.info('...
// etc. etc.
But now I see things like
diagLogger && diagLogger.debug('xhr success', body);
This solution was suppose to make it lighter smaller and easier. But what we have now is a lot of new unnecessary duplicated code which completely changed the initial idea and for me it is not how it should work.
Also the migration information in README.md
just shows the complexity of this solution too. It is just over engineered.
Hi Bart, I completely disagree with your assessment.
This is exactly what we have available.
The additional code (specifically the And at the end of the day this falls back to Which brings me to the And yes, there are also several additional logging functions / levels, and these will become more useful as we unify the code to only use the single
These 2 instances are because the current implementations pass the diagLogger as the 3rd argument and before any optional arguments. For this there are 2 basic options.
100% disagree with this statement, this is removing duplicated code from across the repo... Where is it duplicated? Basic usage is now
As for the extra helpers defined in this section
This is the only portion of your response where I partially agree and it's only in relation to the So you have requested changes, but what exactly are the changes you are suggesting?
|
If you look at If I were to implement this later or now I would still make it differently than having some api helpers functions for parsing config etc.. I would create one class some
This way if you want to allow setting a different logger you can do it easily just extend class and then instead of
But once more we can extend anything (exporters, instrumentation, providers etc.) with
Summarizing in a short
And lastly after these changes the upgrade guide in readme will become this (without allowing yet to set individual logger) |
….NoopLogger and core.ConsoleLogger
76413f0
to
f191b10
Compare
* Public reference to the protected BasePlugin `_logger` instance to be used by this | ||
* plugin's external helper functions | ||
*/ | ||
get logger(): Logger { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out this was the only getter and after refactoring to only use api.diag, this appears to be a safe removal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the getter we were talking about was changing the plugin/instrumentation base logger properties to be getters that pointed to diag to have a point to add a namespace easily in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like very nearly exactly what we talked about yesterday thanks for making the changes. Aside from the two getter comments I made I'm happy with this and will leave my green check in place :)
@@ -27,7 +27,6 @@ export abstract class BaseAbstractPlugin<T> implements Plugin<T> { | |||
protected _config!: PluginConfig; | |||
protected _internalFilesExports!: { [module: string]: unknown }; // output for internalFilesExports | |||
protected readonly _internalFilesList?: PluginInternalFiles; // required for internalFilesExports | |||
protected _logger!: Logger; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this was going to point to api.diag
so we could prevent breaking existing plugins
@@ -40,12 +39,8 @@ | |||
enabled: true, | |||
...config, | |||
}; | |||
this._logger = this._config.logger || new api.NoopLogger(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. I thought we were going to have a getter to api.diag
here so that we would have a place to easily add a namespace in the future. For example in the future it could be populated with some logger created by api.diag.withNamespace(instrumentationName)
return (ex: Exception) => { | ||
logger!.error(stringifyException(ex)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we could remove the loggingErrorHandler
so we only the use the diag logger in a future PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I think we should keep it. The global error handler serves a different (though related) function and having an option to easily push those errors to logs is probably what most people will want most of the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well its purpose was for internal components (exporters etc) so i'm not sure why we could not use the diag logger instead ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This gives users the option to trigger some behavior on an unexpected instrumentation failure like restarting the service or preventing startup or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i prefer this design, it match how other API namespace works so 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes looks great, they are just few minor things that left including readme upgrade guidelines
benchmark/tracer.js
Outdated
@@ -4,7 +4,8 @@ const benchmark = require('./benchmark'); | |||
const opentelemetry = require('../packages/opentelemetry-api'); | |||
const { BasicTracerProvider, BatchSpanProcessor, InMemorySpanExporter, SimpleSpanProcessor } = require('../packages/opentelemetry-tracing'); | |||
|
|||
const diagLogger = opentelemetry.createNoopDiagLogger(); | |||
// Clear any previous global logger | |||
opentelemetry.diag.setLogger(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess opentelemetry.diag.setLogger()
should also set noop logger ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling setLogger() with a "falsey" value will default to a noop implementation
} | ||
}); | ||
}); | ||
|
||
levelMap.forEach(masterLevelMap => { | ||
it(`diag setLogLevel is not ignored when set to ${masterLevelMap.message} and using default logger to log ${fName} message with ${map.message} level`, () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: split it into more levels, when using word "when" - then just add "describe"
describe('when logger is set to ${masterLevelMap.message}', ()=> {
it('should .....'
describe('AND using default logger .....
it('should .........
})
This is not a blocker, it is nice to have for better readability and testing
const { NodeTracerProvider } = require("@opentelemetry/node"); | ||
const { SimpleSpanProcessor } = require("@opentelemetry/tracing"); | ||
const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); | ||
const { registerInstrumentations } = require('@opentelemetry/instrumentation'); | ||
|
||
const provider = new NodeTracerProvider({ logLevel: LogLevel.ERROR }); | ||
const provider = new NodeTracerProvider({ diagLogLevel: DiagLogLevel.ERROR }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be removed
const provider = new NodeTracerProvider({ diagLogLevel: DiagLogLevel.ERROR }); | |
const provider = new NodeTracerProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should
const provider: NodeTracerProvider = new NodeTracerProvider({ | ||
logLevel: LogLevel.ERROR, | ||
diagLogLevel: DiagLogLevel.ERROR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here the same the diagLogLevel
should be removed
@@ -23,7 +23,7 @@ import { AlwaysOnSampler, getEnv } from '@opentelemetry/core'; | |||
* used to extend the default value. | |||
*/ | |||
export const DEFAULT_CONFIG = { | |||
logLevel: getEnv().OTEL_LOG_LEVEL, | |||
diagLogLevel: getEnv().OTEL_LOG_LEVEL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be removed ?
@@ -44,7 +37,7 @@ export interface MeterConfig { | |||
|
|||
/** Default Meter configuration. */ | |||
export const DEFAULT_CONFIG = { | |||
logLevel: getEnv().OTEL_LOG_LEVEL, | |||
diagLogLevel: getEnv().OTEL_LOG_LEVEL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be removed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catches, I obviously missed diagLogLevel removals -- will update (remove) all.
@@ -244,6 +244,156 @@ To request automatic tracing support for a module not on this list, please [file | |||
|
|||
## Upgrade guidelines | |||
|
|||
### 0.17.0 to ??? | |||
|
|||
[PR-1880](https://github.com/open-telemetry/opentelemetry-js/pull/1880) feat(diag-logger): introduce a new global level api.diag for internal diagnostic logging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we agreed that this whole readme section will become also much smaller and simpler.
From a user perspective we have to mention the basic scenarios, So I would keep this only:
Defining logger via config option has been removed in favor of global diag logger.
- Setting logger
import { DiagLogLevel, DiagConsoleLogger, diag } from "@opentelemetry/api";
diag.setLogger(new DiagConsoleLogger());
diag.setLogLevel(DiagLogLevel.ERROR);
- Using logger anywhere in a code
import { diag } from "@opentelemetry/api";
diag.debug("...");
- Setting logger back to noop
import { diag } from "@opentelemetry/api";
diag.setLogger();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I contemplated that -- which is why I also added the recommended approach to each.
Will remove the "get compiling" steps as it's mostly obvious now I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, thx for changes
Which problem is this PR solving?
api.diag
DiagLogger
implementation.Short description of the changes
This PR is a breaking change for all uses of the previous api.Logger, api.NoopLogger, core.LogLevel and core.ConsoleLogger
api.Logger
interfaceapi.NoopLogger
classcore.LogLevel
enumcore.ConsoleLogger
core.LogLevel
toapi.DiagLogLevel
DiagLoggerConfig
interface for defining the optionalDiagLogger
andDiagLogLevel
instances all configurations that previously defined these in their own definitions.logger
properties todiagLogger