[8.16] [Feature Flags] ECS-compliant logger (#214231) (#214353)

# Backport

This will backport the following commits from `main` to `8.16`:
- [[Feature Flags] ECS-compliant logger
(#214231)](https://github.com/elastic/kibana/pull/214231)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Alejandro Fernández
Haro","email":"alejandro.haro@elastic.co"},"sourceCommit":{"committedDate":"2025-03-12T23:24:40Z","message":"[Feature
Flags] ECS-compliant logger (#214231)\n\n## Summary\n\nThe OpenFeature
clients receive a logger, but it logs errors like\n`log('something went
wrong', error)`. Our core logger then removes the\n`error.message` as it
prefers the message provided as the first\nargument.\n\nThis PR wraps
the logger to make sure that we handle this type of usage.\n\ncc
@pmuellr as he found out about this bug\n\n\n### Checklist\n\n- [x]
[Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"98986a86a1086d0047d60a14425920b3c5fbc343","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Core","release_note:skip","v9.0.0","backport:prev-minor","backport:prev-major","v9.1.0"],"title":"[Feature
Flags] ECS-compliant
logger","number":214231,"url":"https://github.com/elastic/kibana/pull/214231","mergeCommit":{"message":"[Feature
Flags] ECS-compliant logger (#214231)\n\n## Summary\n\nThe OpenFeature
clients receive a logger, but it logs errors like\n`log('something went
wrong', error)`. Our core logger then removes the\n`error.message` as it
prefers the message provided as the first\nargument.\n\nThis PR wraps
the logger to make sure that we handle this type of usage.\n\ncc
@pmuellr as he found out about this bug\n\n\n### Checklist\n\n- [x]
[Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"98986a86a1086d0047d60a14425920b3c5fbc343"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/214304","number":214304,"state":"MERGED","mergeCommit":{"sha":"fa04dc0e0536ced502e3eb8993aa7ba227f7299d","message":"[9.0]
[Feature Flags] ECS-compliant logger (#214231) (#214304)\n\n#
Backport\n\nThis will backport the following commits from `main` to
`9.0`:\n- [[Feature Flags] ECS-compliant
logger\n(#214231)](https://github.com/elastic/kibana/pull/214231)\n\n\n\n###
Questions ?\nPlease refer to the [Backport
tool\ndocumentation](https://github.com/sorenlouv/backport)\n\n\n\nCo-authored-by:
Alejandro Fernández Haro
<alejandro.haro@elastic.co>"}},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/214231","number":214231,"mergeCommit":{"message":"[Feature
Flags] ECS-compliant logger (#214231)\n\n## Summary\n\nThe OpenFeature
clients receive a logger, but it logs errors like\n`log('something went
wrong', error)`. Our core logger then removes the\n`error.message` as it
prefers the message provided as the first\nargument.\n\nThis PR wraps
the logger to make sure that we handle this type of usage.\n\ncc
@pmuellr as he found out about this bug\n\n\n### Checklist\n\n- [x]
[Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common
scenarios\n\n---------\n\nCo-authored-by: kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"98986a86a1086d0047d60a14425920b3c5fbc343"}}]}]
BACKPORT-->
This commit is contained in:
Alejandro Fernández Haro 2025-03-13 14:50:49 +01:00 committed by GitHub
parent 21fa4b5b22
commit 8020063671
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 104 additions and 1 deletions

View file

@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import type { Logger as OpenFeatureLogger } from '@openfeature/server-sdk';
import { type MockedLogger, loggerMock } from '@kbn/logging-mocks';
import { createOpenFeatureLogger } from './create_open_feature_logger';
const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;
describe('createOpenFeatureLogger', () => {
let kbnLogger: MockedLogger;
let openFeatureLogger: OpenFeatureLogger;
beforeEach(() => {
kbnLogger = loggerMock.create();
openFeatureLogger = createOpenFeatureLogger(kbnLogger);
});
test.each(LOG_LEVELS)('should log.%s() a simple message', (logLevel) => {
openFeatureLogger[logLevel]('message');
expect(kbnLogger[logLevel]).toHaveBeenCalledWith('message', { extraArguments: [] });
});
test.each(LOG_LEVELS)('should log.%s() a message with 1 argument (non-error)', (logLevel) => {
openFeatureLogger[logLevel]('message', 'something else');
expect(kbnLogger[logLevel]).toHaveBeenCalledWith('message', {
extraArguments: ['something else'],
});
});
test.each(LOG_LEVELS)(
'should log.%s() a message with 1 argument (error) in their expected ECS field',
(logLevel) => {
const error = new Error('Something went wrong');
openFeatureLogger[logLevel]('An error occurred:', error);
expect(kbnLogger[logLevel]).toHaveBeenCalledWith('An error occurred:', { error });
}
);
test.each(LOG_LEVELS)('should log.%s() a message with additional arguments', (logLevel) => {
openFeatureLogger[logLevel]('message', 'something else', 'another thing', { foo: 'bar' });
expect(kbnLogger[logLevel]).toHaveBeenCalledWith('message', {
extraArguments: ['something else', 'another thing', { foo: 'bar' }],
});
});
});

View file

@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import type { Logger as OpenFeatureLogger } from '@openfeature/server-sdk';
import type { Logger, LogMeta } from '@kbn/logging';
interface LogMetaWithExtraArguments extends LogMeta {
extraArguments: unknown[];
}
function normalizeLogArguments(
logger: Logger,
logLevel: 'debug' | 'info' | 'warn' | 'error',
message: string,
...args: unknown[]
) {
// Special case when calling log('something went wrong', error)
if (args.length === 1 && args[0] instanceof Error) {
logger[logLevel](message, { error: args[0] });
} else {
logger[logLevel]<LogMetaWithExtraArguments>(message, { extraArguments: args });
}
}
/**
* The way OpenFeature logs messages is very similar to the console.log approach,
* which is not compatible with our LogMeta approach. This can result in our log removing information like any 3rd+
* arguments passed or the error.message when using log('message', error).
*
* This wrapper addresses this by making it ECS-compliant.
* @param logger The Kibana logger
*/
export function createOpenFeatureLogger(logger: Logger): OpenFeatureLogger {
return {
debug: (message: string, ...args: unknown[]) =>
normalizeLogArguments(logger, 'debug', message, ...args),
info: (message: string, ...args: unknown[]) =>
normalizeLogArguments(logger, 'info', message, ...args),
warn: (message: string, ...args: unknown[]) =>
normalizeLogArguments(logger, 'warn', message, ...args),
error: (message: string, ...args: unknown[]) =>
normalizeLogArguments(logger, 'error', message, ...args),
};
}

View file

@ -24,6 +24,7 @@ import {
} from '@openfeature/server-sdk';
import deepMerge from 'deepmerge';
import { filter, switchMap, startWith, Subject } from 'rxjs';
import { createOpenFeatureLogger } from './create_open_feature_logger';
import { setProviderWithRetries } from './set_provider_with_retries';
import { type FeatureFlagsConfig, featureFlagsConfig } from './feature_flags_config';
@ -55,7 +56,7 @@ export class FeatureFlagsService {
constructor(private readonly core: CoreContext) {
this.logger = core.logger.get('feature-flags-service');
this.featureFlagsClient = OpenFeature.getClient();
OpenFeature.setLogger(this.logger.get('open-feature'));
OpenFeature.setLogger(createOpenFeatureLogger(this.logger.get('open-feature')));
}
/**