Unify Kibana & Elasticsearch logging config keys (#90764)

* align logging config with ES. rename kind to type.

* rename file "path" to "fileName"

* rename logger "context" to "name"

* update audit log docs and tests

* update docs

* fix integration tests

* update deprecations for audit appender

* add tests for audit logging deprecations

* fix eslint problem

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Mikhail Shustov 2021-02-16 20:27:25 +01:00 committed by GitHub
parent db6cd8665c
commit 312351c52c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 468 additions and 355 deletions

View file

@ -34,7 +34,7 @@ Customize the configuration for the plugins.data.search context.
core.logging.configure(
of({
appenders: new Map(),
loggers: [{ context: 'search', appenders: ['default'] }]
loggers: [{ name: 'search', appenders: ['default'] }]
})
)

View file

@ -356,26 +356,26 @@ To enable the <<xpack-security-ecs-audit-logging, ECS audit logger>>, specify wh
[source,yaml]
----------------------------------------
xpack.security.audit.appender:
kind: rolling-file
path: ./audit.log
type: rolling-file
fileName: ./audit.log
policy:
kind: time-interval
type: time-interval
interval: 24h <1>
strategy:
kind: numeric
type: numeric
max: 10 <2>
layout:
kind: json
type: json
----------------------------------------
<1> Rotates log files every 24 hours.
<2> Keeps maximum of 10 log files before deleting older ones.
| `xpack.security.audit.appender.kind`
| `xpack.security.audit.appender.type`
| Required. Specifies where audit logs should be written to. Allowed values are `console`, `file`, or `rolling-file`.
Refer to <<audit-logging-file-appender>> and <<audit-logging-rolling-file-appender>> for appender specific settings.
| `xpack.security.audit.appender.layout.kind`
| `xpack.security.audit.appender.layout.type`
| Required. Specifies how audit logs should be formatted. Allowed values are `json` or `pattern`.
Refer to <<audit-logging-pattern-layout>> for layout specific settings.
@ -396,7 +396,7 @@ The `file` appender writes to a file and can be configured using the following s
[cols="2*<"]
|======
| `xpack.security.audit.appender.path`
| `xpack.security.audit.appender.fileName`
| Required. Full file path the log file should be written to.
|======
@ -408,14 +408,14 @@ The `rolling-file` appender writes to a file and rotates it using a rolling stra
[cols="2*<"]
|======
| `xpack.security.audit.appender.path`
| `xpack.security.audit.appender.fileName`
| Required. Full file path the log file should be written to.
| `xpack.security.audit.appender.policy.kind`
| `xpack.security.audit.appender.policy.type`
| Specifies when a rollover should occur. Allowed values are `size-limit` and `time-interval`. *Default:* `time-interval`.
Refer to <<audit-logging-size-limit-policy>> and <<audit-logging-time-interval-policy>> for policy specific settings.
| `xpack.security.audit.appender.strategy.kind`
| `xpack.security.audit.appender.strategy.type`
| Specifies how the rollover should occur. Only allowed value is currently `numeric`. *Default:* `numeric`
Refer to <<audit-logging-numeric-strategy>> for strategy specific settings.

View file

@ -68,10 +68,10 @@ exports[`#get correctly handles silent logging config. 1`] = `
Object {
"appenders": Object {
"default": Object {
"kind": "legacy-appender",
"legacyLoggingConfig": Object {
"silent": true,
},
"type": "legacy-appender",
},
},
"loggers": undefined,
@ -85,12 +85,12 @@ exports[`#get correctly handles verbose file logging config with json format. 1`
Object {
"appenders": Object {
"default": Object {
"kind": "legacy-appender",
"legacyLoggingConfig": Object {
"dest": "/some/path.log",
"json": true,
"verbose": true,
},
"type": "legacy-appender",
},
},
"loggers": undefined,

View file

@ -44,7 +44,7 @@ export class LegacyObjectToConfigAdapter extends ObjectToConfigAdapter {
const loggingConfig = {
appenders: {
...appenders,
default: { kind: 'legacy-appender', legacyLoggingConfig },
default: { type: 'legacy-appender', legacyLoggingConfig },
},
root: { level: 'info', ...root },
loggers,

View file

@ -226,7 +226,7 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
logging: {
appendersTypesUsed: Array.from(
Array.from(this.loggingConfig?.appenders.values() ?? [])
.reduce((acc, a) => acc.add(a.kind), new Set<string>())
.reduce((acc, a) => acc.add(a.type), new Set<string>())
.values()
),
loggersConfiguredCount: this.loggingConfig?.loggers.length ?? 0,

View file

@ -50,16 +50,16 @@ describe('request logging', () => {
silent: true,
appenders: {
'test-console': {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
pattern: '%level|%logger|%message|%meta',
},
},
},
loggers: [
{
context: 'http.server.response',
name: 'http.server.response',
appenders: ['test-console'],
level: 'debug',
},
@ -96,16 +96,16 @@ describe('request logging', () => {
silent: true,
appenders: {
'test-console': {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
pattern: '%level|%logger|%message|%meta',
},
},
},
loggers: [
{
context: 'http.server.response',
name: 'http.server.response',
appenders: ['test-console'],
level: 'debug',
},

View file

@ -29,16 +29,16 @@ function createRoot(legacyLoggingConfig: LegacyLoggingConfig = {}) {
// platform config
appenders: {
'test-console': {
kind: 'console',
type: 'console',
layout: {
highlight: false,
kind: 'pattern',
type: 'pattern',
},
},
},
loggers: [
{
context: 'test-file',
name: 'test-file',
appenders: ['test-console'],
level: 'info',
},

View file

@ -16,13 +16,13 @@ afterEach(() => (LegacyLoggingServer as any).mockClear());
test('`configSchema` creates correct schema.', () => {
const appenderSchema = LegacyAppender.configSchema;
const validConfig = { kind: 'legacy-appender', legacyLoggingConfig: { verbose: true } };
const validConfig = { type: 'legacy-appender', legacyLoggingConfig: { verbose: true } };
expect(appenderSchema.validate(validConfig)).toEqual({
kind: 'legacy-appender',
type: 'legacy-appender',
legacyLoggingConfig: { verbose: true },
});
const wrongConfig = { kind: 'not-legacy-appender' };
const wrongConfig = { type: 'not-legacy-appender' };
expect(() => appenderSchema.validate(wrongConfig)).toThrow();
});

View file

@ -12,7 +12,7 @@ import { DisposableAppender, LogRecord } from '@kbn/logging';
import { LegacyVars } from '../../types';
export interface LegacyAppenderConfig {
kind: 'legacy-appender';
type: 'legacy-appender';
legacyLoggingConfig?: any;
}
@ -22,7 +22,7 @@ export interface LegacyAppenderConfig {
*/
export class LegacyAppender implements DisposableAppender {
public static configSchema = schema.object({
kind: schema.literal('legacy-appender'),
type: schema.literal('legacy-appender'),
legacyLoggingConfig: schema.any(),
});

View file

@ -24,7 +24,7 @@ Kibana logging system has three main components: _loggers_, _appenders_ and _lay
messages according to message type and level, and to control how these messages are formatted and where the final logs
will be displayed or stored.
__Loggers__ define what logging settings should be applied at the particular context.
__Loggers__ define what logging settings should be applied at the particular context name.
__Appenders__ define where log messages are displayed (eg. stdout or console) and stored (eg. file on the disk).
@ -33,17 +33,17 @@ __Layouts__ define how log messages are formatted and what type of information t
## Logger hierarchy
Every logger has its unique name or context that follows hierarchical naming rule. The logger is considered to be an
Every logger has its unique context name that follows hierarchical naming rule. The logger is considered to be an
ancestor of another logger if its name followed by a `.` is a prefix of the descendant logger name. For example logger
with `a.b` context is an ancestor of logger with `a.b.c` context. All top-level loggers are descendants of special
logger with `root` context that resides at the top of the logger hierarchy. This logger always exists and
with `a.b` context name is an ancestor of logger with `a.b.c` context name. All top-level loggers are descendants of special
logger with `root` context name that resides at the top of the logger hierarchy. This logger always exists and
fully configured.
Developer can configure _log level_ and _appenders_ that should be used within particular context. If logger configuration
Developer can configure _log level_ and _appenders_ that should be used within particular context name. If logger configuration
specifies only _log level_ then _appenders_ configuration will be inherited from the ancestor logger.
__Note:__ in the current implementation log messages are only forwarded to appenders configured for a particular logger
context or to appenders of the closest ancestor if current logger doesn't have any appenders configured. That means that
context name or to appenders of the closest ancestor if current logger doesn't have any appenders configured. That means that
we __don't support__ so called _appender additivity_ when log messages are forwarded to _every_ distinct appender within
ancestor chain including `root`.
@ -55,7 +55,7 @@ A log record is being logged by the logger if its level is higher than or equal
the log record is ignored.
The _all_ and _off_ levels can be used only in configuration and are just handy shortcuts that allow developer to log every
log record or disable logging entirely for the specific context.
log record or disable logging entirely for the specific context name.
## Layouts
@ -129,7 +129,7 @@ Example of `%date` output:
Outputs the process ID.
### JSON layout
With `json` layout log messages will be formatted as JSON strings that include timestamp, log level, context, message
With `json` layout log messages will be formatted as JSON strings that include timestamp, log level, context name, message
text and any other metadata that may be associated with the log message itself.
## Appenders
@ -153,15 +153,15 @@ This policy will rotate the file when it reaches a predetermined size.
logging:
appenders:
rolling-file:
kind: rolling-file
path: /var/logs/kibana.log
type: rolling-file
fileName: /var/logs/kibana.log
policy:
kind: size-limit
type: size-limit
size: 50mb
strategy:
//...
layout:
kind: pattern
type: pattern
```
The options are:
@ -180,16 +180,16 @@ This policy will rotate the file every given interval of time.
logging:
appenders:
rolling-file:
kind: rolling-file
path: /var/logs/kibana.log
type: rolling-file
fileName: /var/logs/kibana.log
policy:
kind: time-interval
type: time-interval
interval: 10s
modulate: true
strategy:
//...
layout:
kind: pattern
type: pattern
```
The options are:
@ -225,16 +225,16 @@ and will retains a fixed amount of rolled files.
logging:
appenders:
rolling-file:
kind: rolling-file
path: /var/logs/kibana.log
type: rolling-file
fileName: /var/logs/kibana.log
policy:
// ...
strategy:
kind: numeric
type: numeric
pattern: '-%i'
max: 2
layout:
kind: pattern
type: pattern
```
For example, with this configuration:
@ -253,7 +253,7 @@ The options are:
The suffix to append to the file path when rolling. Must include `%i`, as this is the value
that will be converted to the file index.
for example, with `path: /var/logs/kibana.log` and `pattern: '-%i'`, the created rolling files
for example, with `fileName: /var/logs/kibana.log` and `pattern: '-%i'`, the created rolling files
will be `/var/logs/kibana-1.log`, `/var/logs/kibana-2.log`, and so on.
The default value is `-%i`
@ -278,49 +278,49 @@ Here is the configuration example that can be used to configure _loggers_, _appe
logging:
appenders:
console:
kind: console
type: console
layout:
kind: pattern
type: pattern
highlight: true
file:
kind: file
path: /var/log/kibana.log
type: file
fileName: /var/log/kibana.log
layout:
kind: pattern
type: pattern
custom:
kind: console
type: console
layout:
kind: pattern
type: pattern
pattern: "[%date][%level] %message"
json-file-appender:
kind: file
path: /var/log/kibana-json.log
type: file
fileName: /var/log/kibana-json.log
root:
appenders: [console, file]
level: error
loggers:
- context: plugins
- name: plugins
appenders: [custom]
level: warn
- context: plugins.myPlugin
- name: plugins.myPlugin
level: info
- context: server
- name: server
level: fatal
- context: optimize
- name: optimize
appenders: [console]
- context: telemetry
- name: telemetry
level: all
appenders: [json-file-appender]
- context: metrics.ops
- name: metrics.ops
level: debug
appenders: [console]
```
Here is what we get with the config above:
| Context | Appenders | Level |
| Context name | Appenders | Level |
| ---------------- |:------------------------:| -----:|
| root | console, file | error |
| plugins | custom | warn |
@ -331,7 +331,7 @@ Here is what we get with the config above:
| metrics.ops | console | debug |
The `root` logger has a dedicated configuration node since this context is special and should always exist. By
The `root` logger has a dedicated configuration node since this context name is special and should always exist. By
default `root` is configured with `info` level and `default` appender that is also always available. This is the
configuration that all custom loggers will use unless they're re-configured explicitly.
@ -391,7 +391,7 @@ The message contains some high-level information, and the corresponding log meta
## Usage
Usage is very straightforward, one should just get a logger for a specific context and use it to log messages with
Usage is very straightforward, one should just get a logger for a specific context name and use it to log messages with
different log level.
```typescript
@ -409,7 +409,7 @@ loggerWithNestedContext.trace('Message with `trace` log level.');
loggerWithNestedContext.debug('Message with `debug` log level.');
```
And assuming logger for `server` context with `console` appender and `trace` level was used, console output will look like this:
And assuming logger for `server` name with `console` appender and `trace` level was used, console output will look like this:
```bash
[2017-07-25T11:54:41.639-07:00][TRACE][server] Message with `trace` log level.
[2017-07-25T11:54:41.639-07:00][DEBUG][server] Message with `debug` log level.
@ -422,7 +422,7 @@ And assuming logger for `server` context with `console` appender and `trace` lev
[2017-07-25T11:54:41.639-07:00][DEBUG][server.http] Message with `debug` log level.
```
The log will be less verbose with `warn` level for the `server` context:
The log will be less verbose with `warn` level for the `server` context name:
```bash
[2017-07-25T11:54:41.639-07:00][WARN ][server] Message with `warn` log level.
[2017-07-25T11:54:41.639-07:00][ERROR][server] Message with `error` log level.
@ -433,7 +433,7 @@ The log will be less verbose with `warn` level for the `server` context:
Compatibility with the legacy logging system is assured until the end of the `v7` version.
All log messages handled by `root` context are forwarded to the legacy logging service. If you re-write
root appenders, make sure that it contains `default` appender to provide backward compatibility.
**Note**: If you define an appender for a context, the log messages aren't handled by the
**Note**: If you define an appender for a context name, the log messages aren't handled by the
`root` context anymore and not forwarded to the legacy logging service.
#### logging.dest
@ -442,21 +442,21 @@ define a custom one.
```yaml
logging:
loggers:
- context: plugins.myPlugin
- name: plugins.myPlugin
appenders: [console]
```
Logs in a *file* if given file path. You should define a custom appender with `kind: file`
Logs in a *file* if given file path. You should define a custom appender with `type: file`
```yaml
logging:
appenders:
file:
kind: file
path: /var/log/kibana.log
type: file
fileName: /var/log/kibana.log
layout:
kind: pattern
type: pattern
loggers:
- context: plugins.myPlugin
- name: plugins.myPlugin
appenders: [file]
```
#### logging.json
@ -468,7 +468,7 @@ Suppresses all logging output other than error messages. With new logging, confi
with adjusting minimum required [logging level](#log-level).
```yaml
loggers:
- context: plugins.myPlugin
- name: plugins.myPlugin
appenders: [console]
level: error
# or for all output
@ -494,32 +494,32 @@ to [specify timezone](#date) for `layout: pattern`. Defaults to host timezone wh
logging:
appenders:
custom-console:
kind: console
type: console
layout:
kind: pattern
type: pattern
highlight: true
pattern: "[%level] [%date{ISO8601_TZ}{America/Los_Angeles}][%logger] %message"
```
#### logging.events
Define a custom logger for a specific context.
Define a custom logger for a specific context name.
**`logging.events.ops`** outputs sample system and process information at a regular interval.
With the new logging config, these are provided by a dedicated [context](#logger-hierarchy),
With the new logging config, these are provided by a dedicated [context name](#logger-hierarchy),
and you can enable them by adjusting the minimum required [logging level](#log-level) to `debug`:
```yaml
loggers:
- context: metrics.ops
- name: metrics.ops
appenders: [console]
level: debug
```
**`logging.events.request` and `logging.events.response`** provide logs for each request handled
by the http service. With the new logging config, these are provided by a dedicated [context](#logger-hierarchy),
by the http service. With the new logging config, these are provided by a dedicated [context name](#logger-hierarchy),
and you can enable them by adjusting the minimum required [logging level](#log-level) to `debug`:
```yaml
loggers:
- context: http.server.response
- name: http.server.response
appenders: [console]
level: debug
```
@ -532,7 +532,7 @@ TBD
| Parameter | Platform log record in **pattern** format | Legacy Platform log record **text** format |
| --------------- | ------------------------------------------ | ------------------------------------------ |
| @timestamp | ISO8601_TZ `2012-01-31T23:33:22.011-05:00` | Absolute `23:33:22.011` |
| context | `parent.child` | `['parent', 'child']` |
| context name | `parent.child` | `['parent', 'child']` |
| level | `DEBUG` | `['debug']` |
| meta | stringified JSON object `{"to": "v8"}` | N/A |
| pid | can be configured as `%pid` | N/A |
@ -540,9 +540,9 @@ TBD
| Parameter | Platform log record in **json** format | Legacy Platform log record **json** format |
| --------------- | ------------------------------------------ | -------------------------------------------- |
| @timestamp | ISO8601_TZ `2012-01-31T23:33:22.011-05:00` | ISO8601 `2012-01-31T23:33:22.011Z` |
| context | `context: parent.child` | `tags: ['parent', 'child']` |
| level | `level: DEBUG` | `tags: ['debug']` |
| context name | `log.logger: parent.child` | `tags: ['parent', 'child']` |
| level | `log.level: DEBUG` | `tags: ['debug']` |
| meta | separate property `"meta": {"to": "v8"}` | merged in log record `{... "to": "v8"}` |
| pid | `pid: 12345` | `pid: 12345` |
| pid | `process.pid: 12345` | `pid: 12345` |
| type | N/A | `type: log` |
| error | `{ message, name, stack }` | `{ message, name, stack, code, signal }` |

View file

@ -84,7 +84,7 @@ Object {
}
`;
exports[`uses \`root\` logger if context is not specified. 1`] = `
exports[`uses \`root\` logger if context name is not specified. 1`] = `
Array [
Array [
"[2012-01-31T03:33:22.011-05:00][INFO ][root] This message goes to a root context.",

View file

@ -12,7 +12,7 @@ jest.mock('../layouts/layouts', () => {
const { schema } = require('@kbn/config-schema');
return {
Layouts: {
configSchema: schema.object({ kind: schema.literal('mock') }),
configSchema: schema.object({ type: schema.literal('mock') }),
create: mockCreateLayout,
},
};

View file

@ -21,33 +21,33 @@ beforeEach(() => {
test('`configSchema` creates correct schema.', () => {
const appendersSchema = Appenders.configSchema;
const validConfig1 = { kind: 'file', layout: { kind: 'mock' }, path: 'path' };
const validConfig1 = { type: 'file', layout: { type: 'mock' }, fileName: 'path' };
expect(appendersSchema.validate(validConfig1)).toEqual({
kind: 'file',
layout: { kind: 'mock' },
path: 'path',
type: 'file',
layout: { type: 'mock' },
fileName: 'path',
});
const validConfig2 = { kind: 'console', layout: { kind: 'mock' } };
const validConfig2 = { type: 'console', layout: { type: 'mock' } };
expect(appendersSchema.validate(validConfig2)).toEqual({
kind: 'console',
layout: { kind: 'mock' },
type: 'console',
layout: { type: 'mock' },
});
const wrongConfig1 = {
kind: 'console',
layout: { kind: 'mock' },
path: 'path',
type: 'console',
layout: { type: 'mock' },
fileName: 'path',
};
expect(() => appendersSchema.validate(wrongConfig1)).toThrow();
const wrongConfig2 = { kind: 'file', layout: { kind: 'mock' } };
const wrongConfig2 = { type: 'file', layout: { type: 'mock' } };
expect(() => appendersSchema.validate(wrongConfig2)).toThrow();
const wrongConfig3 = {
kind: 'console',
layout: { kind: 'mock' },
path: 'path',
type: 'console',
layout: { type: 'mock' },
fileName: 'path',
};
expect(() => appendersSchema.validate(wrongConfig3)).toThrow();
});
@ -56,31 +56,31 @@ test('`create()` creates correct appender.', () => {
mockCreateLayout.mockReturnValue({ format: () => '' });
const consoleAppender = Appenders.create({
kind: 'console',
layout: { highlight: true, kind: 'pattern', pattern: '' },
type: 'console',
layout: { highlight: true, type: 'pattern', pattern: '' },
});
expect(consoleAppender).toBeInstanceOf(ConsoleAppender);
const fileAppender = Appenders.create({
kind: 'file',
layout: { highlight: true, kind: 'pattern', pattern: '' },
path: 'path',
type: 'file',
layout: { highlight: true, type: 'pattern', pattern: '' },
fileName: 'path',
});
expect(fileAppender).toBeInstanceOf(FileAppender);
const legacyAppender = Appenders.create({
kind: 'legacy-appender',
type: 'legacy-appender',
legacyLoggingConfig: { verbose: true },
});
expect(legacyAppender).toBeInstanceOf(LegacyAppender);
const rollingFileAppender = Appenders.create({
kind: 'rolling-file',
path: 'path',
layout: { highlight: true, kind: 'pattern', pattern: '' },
strategy: { kind: 'numeric', max: 5, pattern: '%i' },
policy: { kind: 'size-limit', size: ByteSizeValue.parse('15b') },
type: 'rolling-file',
fileName: 'path',
layout: { highlight: true, type: 'pattern', pattern: '' },
strategy: { type: 'numeric', max: 5, pattern: '%i' },
policy: { type: 'size-limit', size: ByteSizeValue.parse('15b') },
});
expect(rollingFileAppender).toBeInstanceOf(RollingFileAppender);
});

View file

@ -52,11 +52,11 @@ export class Appenders {
* @returns Fully constructed `Appender` instance.
*/
public static create(config: AppenderConfigType): DisposableAppender {
switch (config.kind) {
switch (config.type) {
case 'console':
return new ConsoleAppender(Layouts.create(config.layout));
case 'file':
return new FileAppender(Layouts.create(config.layout), config.path);
return new FileAppender(Layouts.create(config.layout), config.fileName);
case 'rolling-file':
return new RollingFileAppender(config);
case 'legacy-appender':

View file

@ -12,7 +12,7 @@ jest.mock('../../layouts/layouts', () => {
return {
Layouts: {
configSchema: schema.object({
kind: schema.literal('mock'),
type: schema.literal('mock'),
}),
},
};
@ -23,16 +23,16 @@ import { ConsoleAppender } from './console_appender';
test('`configSchema` creates correct schema.', () => {
const appenderSchema = ConsoleAppender.configSchema;
const validConfig = { kind: 'console', layout: { kind: 'mock' } };
const validConfig = { type: 'console', layout: { type: 'mock' } };
expect(appenderSchema.validate(validConfig)).toEqual({
kind: 'console',
layout: { kind: 'mock' },
type: 'console',
layout: { type: 'mock' },
});
const wrongConfig1 = { kind: 'not-console', layout: { kind: 'mock' } };
const wrongConfig1 = { type: 'not-console', layout: { type: 'mock' } };
expect(() => appenderSchema.validate(wrongConfig1)).toThrow();
const wrongConfig2 = { kind: 'file', layout: { kind: 'mock' }, path: 'path' };
const wrongConfig2 = { type: 'file', layout: { type: 'mock' }, fileName: 'path' };
expect(() => appenderSchema.validate(wrongConfig2)).toThrow();
});

View file

@ -13,7 +13,7 @@ import { Layouts, LayoutConfigType } from '../../layouts/layouts';
const { literal, object } = schema;
export interface ConsoleAppenderConfig {
kind: 'console';
type: 'console';
layout: LayoutConfigType;
}
@ -24,7 +24,7 @@ export interface ConsoleAppenderConfig {
*/
export class ConsoleAppender implements DisposableAppender {
public static configSchema = object({
kind: literal('console'),
type: literal('console'),
layout: Layouts.configSchema,
});

View file

@ -12,7 +12,7 @@ jest.mock('../../layouts/layouts', () => {
return {
Layouts: {
configSchema: schema.object({
kind: schema.literal('mock'),
type: schema.literal('mock'),
}),
},
};

View file

@ -20,24 +20,24 @@ beforeEach(() => {
test('`createConfigSchema()` creates correct schema.', () => {
const appenderSchema = FileAppender.configSchema;
const validConfig = { kind: 'file', layout: { kind: 'mock' }, path: 'path' };
const validConfig = { type: 'file', layout: { type: 'mock' }, fileName: 'path' };
expect(appenderSchema.validate(validConfig)).toEqual({
kind: 'file',
layout: { kind: 'mock' },
path: 'path',
type: 'file',
layout: { type: 'mock' },
fileName: 'path',
});
const wrongConfig1 = {
kind: 'not-file',
layout: { kind: 'mock' },
path: 'path',
type: 'not-file',
layout: { type: 'mock' },
fileName: 'path',
};
expect(() => appenderSchema.validate(wrongConfig1)).toThrow();
const wrongConfig2 = { kind: 'file', layout: { kind: 'mock' } };
const wrongConfig2 = { type: 'file', layout: { type: 'mock' } };
expect(() => appenderSchema.validate(wrongConfig2)).toThrow();
const wrongConfig3 = { kind: 'console', layout: { kind: 'mock' } };
const wrongConfig3 = { type: 'console', layout: { type: 'mock' } };
expect(() => appenderSchema.validate(wrongConfig3)).toThrow();
});

View file

@ -13,9 +13,9 @@ import { createWriteStream, WriteStream } from 'fs';
import { Layouts, LayoutConfigType } from '../../layouts/layouts';
export interface FileAppenderConfig {
kind: 'file';
type: 'file';
layout: LayoutConfigType;
path: string;
fileName: string;
}
/**
@ -24,9 +24,9 @@ export interface FileAppenderConfig {
*/
export class FileAppender implements DisposableAppender {
public static configSchema = schema.object({
kind: schema.literal('file'),
type: schema.literal('file'),
layout: Layouts.configSchema,
path: schema.string(),
fileName: schema.string(),
});
/**

View file

@ -34,7 +34,7 @@ export type TriggeringPolicyConfig =
| TimeIntervalTriggeringPolicyConfig;
const defaultPolicy: TimeIntervalTriggeringPolicyConfig = {
kind: 'time-interval',
type: 'time-interval',
interval: moment.duration(24, 'hour'),
modulate: true,
};
@ -48,7 +48,7 @@ export const createTriggeringPolicy = (
config: TriggeringPolicyConfig,
context: RollingFileContext
): TriggeringPolicy => {
switch (config.kind) {
switch (config.type) {
case 'size-limit':
return new SizeLimitTriggeringPolicy(config, context);
case 'time-interval':

View file

@ -15,7 +15,7 @@ describe('SizeLimitTriggeringPolicy', () => {
let context: RollingFileContext;
const createPolicy = (size: ByteSizeValue) =>
new SizeLimitTriggeringPolicy({ kind: 'size-limit', size }, context);
new SizeLimitTriggeringPolicy({ type: 'size-limit', size }, context);
const createLogRecord = (parts: Partial<LogRecord> = {}): LogRecord => ({
timestamp: new Date(),

View file

@ -12,7 +12,7 @@ import { RollingFileContext } from '../../rolling_file_context';
import { TriggeringPolicy } from '../policy';
export interface SizeLimitTriggeringPolicyConfig {
kind: 'size-limit';
type: 'size-limit';
/**
* The minimum size the file must have to roll over.
@ -21,7 +21,7 @@ export interface SizeLimitTriggeringPolicyConfig {
}
export const sizeLimitTriggeringPolicyConfigSchema = schema.object({
kind: schema.literal('size-limit'),
type: schema.literal('size-limit'),
size: schema.byteSize({ min: '1b', defaultValue: '100mb' }),
});

View file

@ -42,7 +42,7 @@ describe('TimeIntervalTriggeringPolicy', () => {
interval: string = '15m',
modulate: boolean = false
): TimeIntervalTriggeringPolicyConfig => ({
kind: 'time-interval',
type: 'time-interval',
interval: schema.duration().validate(interval),
modulate,
});

View file

@ -15,7 +15,7 @@ import { getNextRollingTime } from './get_next_rolling_time';
import { isValidRolloverInterval } from './utils';
export interface TimeIntervalTriggeringPolicyConfig {
kind: 'time-interval';
type: 'time-interval';
/**
* How often a rollover should occur.
@ -38,7 +38,7 @@ export interface TimeIntervalTriggeringPolicyConfig {
}
export const timeIntervalTriggeringPolicyConfigSchema = schema.object({
kind: schema.literal('time-interval'),
type: schema.literal('time-interval'),
interval: schema.duration({
defaultValue: '24h',
validate: (interval) => {

View file

@ -20,20 +20,20 @@ import { LogLevel, LogRecord } from '@kbn/logging';
import { RollingFileAppender, RollingFileAppenderConfig } from './rolling_file_appender';
const config: RollingFileAppenderConfig = {
kind: 'rolling-file',
path: '/var/log/kibana.log',
type: 'rolling-file',
fileName: '/var/log/kibana.log',
layout: {
kind: 'pattern',
type: 'pattern',
pattern: '%message',
highlight: false,
},
policy: {
kind: 'time-interval',
type: 'time-interval',
interval: moment.duration(4, 'hour'),
modulate: true,
},
strategy: {
kind: 'numeric',
type: 'numeric',
max: 5,
pattern: '-%i',
},
@ -99,7 +99,7 @@ describe('RollingFileAppender', () => {
it('constructs its delegates with the correct parameters', () => {
expect(RollingFileContextMock).toHaveBeenCalledTimes(1);
expect(RollingFileContextMock).toHaveBeenCalledWith(config.path);
expect(RollingFileContextMock).toHaveBeenCalledWith(config.fileName);
expect(RollingFileManagerMock).toHaveBeenCalledTimes(1);
expect(RollingFileManagerMock).toHaveBeenCalledWith(context);

View file

@ -26,7 +26,7 @@ import { RollingFileManager } from './rolling_file_manager';
import { RollingFileContext } from './rolling_file_context';
export interface RollingFileAppenderConfig {
kind: 'rolling-file';
type: 'rolling-file';
/**
* The layout to use when writing log entries
*/
@ -34,7 +34,7 @@ export interface RollingFileAppenderConfig {
/**
* The absolute path of the file to write to.
*/
path: string;
fileName: string;
/**
* The {@link TriggeringPolicy | policy} to use to determine if a rollover should occur.
*/
@ -51,9 +51,9 @@ export interface RollingFileAppenderConfig {
*/
export class RollingFileAppender implements DisposableAppender {
public static configSchema = schema.object({
kind: schema.literal('rolling-file'),
type: schema.literal('rolling-file'),
layout: Layouts.configSchema,
path: schema.string(),
fileName: schema.string(),
policy: triggeringPolicyConfigSchema,
strategy: rollingStrategyConfigSchema,
});
@ -70,7 +70,7 @@ export class RollingFileAppender implements DisposableAppender {
private readonly buffer: BufferAppender;
constructor(config: RollingFileAppenderConfig) {
this.context = new RollingFileContext(config.path);
this.context = new RollingFileContext(config.fileName);
this.context.refreshFileInfo();
this.fileManager = new RollingFileManager(this.context);
this.layout = Layouts.create(config.layout);

View file

@ -19,7 +19,7 @@ export { RollingStrategy } from './strategy';
export type RollingStrategyConfig = NumericRollingStrategyConfig;
const defaultStrategy: NumericRollingStrategyConfig = {
kind: 'numeric',
type: 'numeric',
pattern: '-%i',
max: 7,
};

View file

@ -27,8 +27,8 @@ describe('NumericRollingStrategy', () => {
let context: ReturnType<typeof rollingFileAppenderMocks.createContext>;
let strategy: NumericRollingStrategy;
const createStrategy = (config: Omit<NumericRollingStrategyConfig, 'kind'>) =>
new NumericRollingStrategy({ ...config, kind: 'numeric' }, context);
const createStrategy = (config: Omit<NumericRollingStrategyConfig, 'type'>) =>
new NumericRollingStrategy({ ...config, type: 'numeric' }, context);
beforeEach(() => {
context = rollingFileAppenderMocks.createContext(logFilePath);

View file

@ -19,10 +19,10 @@ import {
} from './rolling_tasks';
export interface NumericRollingStrategyConfig {
kind: 'numeric';
type: 'numeric';
/**
* The suffix pattern to apply when renaming a file. The suffix will be applied
* after the `appender.path` file name, but before the file extension.
* after the `appender.fileName` file name, but before the file extension.
*
* Must include `%i`, as it is the value that will be converted to the file index
*
@ -31,8 +31,8 @@ export interface NumericRollingStrategyConfig {
* logging:
* appenders:
* rolling-file:
* kind: rolling-file
* path: /var/logs/kibana.log
* type: rolling-file
* fileName: /var/logs/kibana.log
* strategy:
* type: default
* pattern: "-%i"
@ -52,7 +52,7 @@ export interface NumericRollingStrategyConfig {
}
export const numericRollingStrategyConfigSchema = schema.object({
kind: schema.literal('numeric'),
type: schema.literal('numeric'),
pattern: schema.string({
defaultValue: '-%i',
validate: (pattern) => {
@ -73,8 +73,8 @@ export const numericRollingStrategyConfigSchema = schema.object({
* logging:
* appenders:
* rolling-file:
* kind: rolling-file
* path: /kibana.log
* type: rolling-file
* fileName: /kibana.log
* strategy:
* type: numeric
* pattern: "-%i"

View file

@ -17,22 +17,22 @@ function createRoot() {
silent: true, // set "true" in kbnTestServer
appenders: {
'test-console': {
kind: 'console',
type: 'console',
layout: {
highlight: false,
kind: 'pattern',
type: 'pattern',
pattern: '%level|%logger|%message',
},
},
},
loggers: [
{
context: 'parent',
name: 'parent',
appenders: ['test-console'],
level: 'warn',
},
{
context: 'parent.child',
name: 'parent.child',
appenders: ['test-console'],
level: 'error',
},
@ -42,7 +42,7 @@ function createRoot() {
}
describe('logging service', () => {
describe('logs according to context hierarchy', () => {
describe('logs according to context name hierarchy', () => {
let root: ReturnType<typeof createRoot>;
let mockConsoleLog: jest.SpyInstance;
beforeAll(async () => {
@ -61,7 +61,7 @@ describe('logging service', () => {
await root.shutdown();
});
it('uses the most specific context', () => {
it('uses the most specific context name', () => {
const logger = root.logger.get('parent.child');
logger.error('error from "parent.child" context');
@ -74,7 +74,7 @@ describe('logging service', () => {
);
});
it('uses parent context', () => {
it('uses parent context name', () => {
const logger = root.logger.get('parent.another-child');
logger.error('error from "parent.another-child" context');
@ -104,31 +104,31 @@ describe('logging service', () => {
});
});
describe('custom context configuration', () => {
describe('custom context name configuration', () => {
const CUSTOM_LOGGING_CONFIG: LoggerContextConfigInput = {
appenders: {
customJsonConsole: {
kind: 'console',
type: 'console',
layout: {
kind: 'json',
type: 'json',
},
},
customPatternConsole: {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
pattern: 'CUSTOM - PATTERN [%logger][%level] %message',
},
},
},
loggers: [
{ context: 'debug_json', appenders: ['customJsonConsole'], level: 'debug' },
{ context: 'debug_pattern', appenders: ['customPatternConsole'], level: 'debug' },
{ context: 'info_json', appenders: ['customJsonConsole'], level: 'info' },
{ context: 'info_pattern', appenders: ['customPatternConsole'], level: 'info' },
{ name: 'debug_json', appenders: ['customJsonConsole'], level: 'debug' },
{ name: 'debug_pattern', appenders: ['customPatternConsole'], level: 'debug' },
{ name: 'info_json', appenders: ['customJsonConsole'], level: 'info' },
{ name: 'info_pattern', appenders: ['customPatternConsole'], level: 'info' },
{
context: 'all',
name: 'all',
appenders: ['customJsonConsole', 'customPatternConsole'],
level: 'debug',
},

View file

@ -25,7 +25,7 @@ function createRoot(appenderConfig: any) {
},
loggers: [
{
context: 'test.rolling.file',
name: 'test.rolling.file',
appenders: ['rolling-file'],
level: 'debug',
},
@ -63,18 +63,18 @@ describe('RollingFileAppender', () => {
describe('`size-limit` policy with `numeric` strategy', () => {
it('rolls the log file in the correct order', async () => {
root = createRoot({
kind: 'rolling-file',
path: logFile,
type: 'rolling-file',
fileName: logFile,
layout: {
kind: 'pattern',
type: 'pattern',
pattern: '%message',
},
policy: {
kind: 'size-limit',
type: 'size-limit',
size: '100b',
},
strategy: {
kind: 'numeric',
type: 'numeric',
max: 5,
pattern: '.%i',
},
@ -108,18 +108,18 @@ describe('RollingFileAppender', () => {
it('only keep the correct number of files', async () => {
root = createRoot({
kind: 'rolling-file',
path: logFile,
type: 'rolling-file',
fileName: logFile,
layout: {
kind: 'pattern',
type: 'pattern',
pattern: '%message',
},
policy: {
kind: 'size-limit',
type: 'size-limit',
size: '60b',
},
strategy: {
kind: 'numeric',
type: 'numeric',
max: 2,
pattern: '-%i',
},
@ -157,19 +157,19 @@ describe('RollingFileAppender', () => {
describe('`time-interval` policy with `numeric` strategy', () => {
it('rolls the log file at the given interval', async () => {
root = createRoot({
kind: 'rolling-file',
path: logFile,
type: 'rolling-file',
fileName: logFile,
layout: {
kind: 'pattern',
type: 'pattern',
pattern: '%message',
},
policy: {
kind: 'time-interval',
type: 'time-interval',
interval: '1s',
modulate: true,
},
strategy: {
kind: 'numeric',
type: 'numeric',
max: 2,
pattern: '-%i',
},

View file

@ -63,7 +63,7 @@ const records: LogRecord[] = [
test('`createConfigSchema()` creates correct schema.', () => {
const layoutSchema = JsonLayout.configSchema;
expect(layoutSchema.validate({ kind: 'json' })).toEqual({ kind: 'json' });
expect(layoutSchema.validate({ type: 'json' })).toEqual({ type: 'json' });
});
test('`format()` correctly formats record.', () => {

View file

@ -14,12 +14,12 @@ import { LogRecord, Layout } from '@kbn/logging';
const { literal, object } = schema;
const jsonLayoutSchema = object({
kind: literal('json'),
type: literal('json'),
});
/** @internal */
export interface JsonLayoutConfigType {
kind: 'json';
type: 'json';
}
/**

View file

@ -12,43 +12,43 @@ import { PatternLayout } from './pattern_layout';
test('`configSchema` creates correct schema for `pattern` layout.', () => {
const layoutsSchema = Layouts.configSchema;
const validConfigWithOptional = { kind: 'pattern' };
const validConfigWithOptional = { type: 'pattern' };
expect(layoutsSchema.validate(validConfigWithOptional)).toEqual({
highlight: undefined,
kind: 'pattern',
type: 'pattern',
pattern: undefined,
});
const validConfig = {
highlight: true,
kind: 'pattern',
type: 'pattern',
pattern: '%message',
};
expect(layoutsSchema.validate(validConfig)).toEqual({
highlight: true,
kind: 'pattern',
type: 'pattern',
pattern: '%message',
});
const wrongConfig2 = { kind: 'pattern', pattern: 1 };
const wrongConfig2 = { type: 'pattern', pattern: 1 };
expect(() => layoutsSchema.validate(wrongConfig2)).toThrow();
});
test('`createConfigSchema()` creates correct schema for `json` layout.', () => {
const layoutsSchema = Layouts.configSchema;
const validConfig = { kind: 'json' };
expect(layoutsSchema.validate(validConfig)).toEqual({ kind: 'json' });
const validConfig = { type: 'json' };
expect(layoutsSchema.validate(validConfig)).toEqual({ type: 'json' });
});
test('`create()` creates correct layout.', () => {
const patternLayout = Layouts.create({
highlight: false,
kind: 'pattern',
type: 'pattern',
pattern: '[%date][%level][%logger] %message',
});
expect(patternLayout).toBeInstanceOf(PatternLayout);
const jsonLayout = Layouts.create({ kind: 'json' });
const jsonLayout = Layouts.create({ type: 'json' });
expect(jsonLayout).toBeInstanceOf(JsonLayout);
});

View file

@ -27,7 +27,7 @@ export class Layouts {
* @returns Fully constructed `Layout` instance.
*/
public static create(config: LayoutConfigType): Layout {
switch (config.kind) {
switch (config.type) {
case 'json':
return new JsonLayout();

View file

@ -66,28 +66,28 @@ expect.addSnapshotSerializer(stripAnsiSnapshotSerializer);
test('`createConfigSchema()` creates correct schema.', () => {
const layoutSchema = PatternLayout.configSchema;
const validConfigWithOptional = { kind: 'pattern' };
const validConfigWithOptional = { type: 'pattern' };
expect(layoutSchema.validate(validConfigWithOptional)).toEqual({
highlight: undefined,
kind: 'pattern',
type: 'pattern',
pattern: undefined,
});
const validConfig = {
highlight: true,
kind: 'pattern',
type: 'pattern',
pattern: '%message',
};
expect(layoutSchema.validate(validConfig)).toEqual({
highlight: true,
kind: 'pattern',
type: 'pattern',
pattern: '%message',
});
const wrongConfig1 = { kind: 'json' };
const wrongConfig1 = { type: 'json' };
expect(() => layoutSchema.validate(wrongConfig1)).toThrow();
const wrongConfig2 = { kind: 'pattern', pattern: 1 };
const wrongConfig2 = { type: 'pattern', pattern: 1 };
expect(() => layoutSchema.validate(wrongConfig2)).toThrow();
});

View file

@ -32,7 +32,7 @@ export const patternSchema = schema.string({
const patternLayoutSchema = schema.object({
highlight: schema.maybe(schema.boolean()),
kind: schema.literal('pattern'),
type: schema.literal('pattern'),
pattern: schema.maybe(patternSchema),
});
@ -47,7 +47,7 @@ const conversions: Conversion[] = [
/** @internal */
export interface PatternLayoutConfigType {
kind: 'pattern';
type: 'pattern';
highlight?: boolean;
pattern?: string;
}

View file

@ -51,12 +51,12 @@ test('correctly fills in default config.', () => {
expect(configValue.appenders.size).toBe(2);
expect(configValue.appenders.get('default')).toEqual({
kind: 'console',
layout: { kind: 'pattern', highlight: true },
type: 'console',
layout: { type: 'pattern', highlight: true },
});
expect(configValue.appenders.get('console')).toEqual({
kind: 'console',
layout: { kind: 'pattern', highlight: true },
type: 'console',
layout: { type: 'pattern', highlight: true },
});
});
@ -65,8 +65,8 @@ test('correctly fills in custom `appenders` config.', () => {
config.schema.validate({
appenders: {
console: {
kind: 'console',
layout: { kind: 'pattern' },
type: 'console',
layout: { type: 'pattern' },
},
},
})
@ -75,13 +75,13 @@ test('correctly fills in custom `appenders` config.', () => {
expect(configValue.appenders.size).toBe(2);
expect(configValue.appenders.get('default')).toEqual({
kind: 'console',
layout: { kind: 'pattern', highlight: true },
type: 'console',
layout: { type: 'pattern', highlight: true },
});
expect(configValue.appenders.get('console')).toEqual({
kind: 'console',
layout: { kind: 'pattern' },
type: 'console',
layout: { type: 'pattern' },
});
});
@ -91,7 +91,7 @@ test('correctly fills in default `loggers` config.', () => {
expect(configValue.loggers.size).toBe(1);
expect(configValue.loggers.get('root')).toEqual({
appenders: ['default'],
context: 'root',
name: 'root',
level: 'info',
});
});
@ -101,24 +101,24 @@ test('correctly fills in custom `loggers` config.', () => {
config.schema.validate({
appenders: {
file: {
kind: 'file',
layout: { kind: 'pattern' },
path: 'path',
type: 'file',
layout: { type: 'pattern' },
fileName: 'path',
},
},
loggers: [
{
appenders: ['file'],
context: 'plugins',
name: 'plugins',
level: 'warn',
},
{
context: 'plugins.pid',
name: 'plugins.pid',
level: 'trace',
},
{
appenders: ['default'],
context: 'http',
name: 'http',
level: 'error',
},
],
@ -128,22 +128,22 @@ test('correctly fills in custom `loggers` config.', () => {
expect(configValue.loggers.size).toBe(4);
expect(configValue.loggers.get('root')).toEqual({
appenders: ['default'],
context: 'root',
name: 'root',
level: 'info',
});
expect(configValue.loggers.get('plugins')).toEqual({
appenders: ['file'],
context: 'plugins',
name: 'plugins',
level: 'warn',
});
expect(configValue.loggers.get('plugins.pid')).toEqual({
appenders: ['file'],
context: 'plugins.pid',
name: 'plugins.pid',
level: 'trace',
});
expect(configValue.loggers.get('http')).toEqual({
appenders: ['default'],
context: 'http',
name: 'http',
level: 'error',
});
});
@ -153,7 +153,7 @@ test('fails if loggers use unknown appenders.', () => {
loggers: [
{
appenders: ['unknown'],
context: 'some.nested.context',
name: 'some.nested.context',
},
],
});
@ -167,9 +167,9 @@ describe('extend', () => {
config.schema.validate({
appenders: {
file1: {
kind: 'file',
layout: { kind: 'pattern' },
path: 'path',
type: 'file',
layout: { type: 'pattern' },
fileName: 'path',
},
},
})
@ -179,9 +179,9 @@ describe('extend', () => {
config.schema.validate({
appenders: {
file2: {
kind: 'file',
layout: { kind: 'pattern' },
path: 'path',
type: 'file',
layout: { type: 'pattern' },
fileName: 'path',
},
},
})
@ -200,9 +200,9 @@ describe('extend', () => {
config.schema.validate({
appenders: {
file1: {
kind: 'file',
layout: { kind: 'pattern' },
path: 'path',
type: 'file',
layout: { type: 'pattern' },
fileName: 'path',
},
},
})
@ -212,18 +212,18 @@ describe('extend', () => {
config.schema.validate({
appenders: {
file1: {
kind: 'file',
layout: { kind: 'json' },
path: 'updatedPath',
type: 'file',
layout: { type: 'json' },
fileName: 'updatedPath',
},
},
})
);
expect(mergedConfigValue.appenders.get('file1')).toEqual({
kind: 'file',
layout: { kind: 'json' },
path: 'updatedPath',
type: 'file',
layout: { type: 'json' },
fileName: 'updatedPath',
});
});
@ -232,7 +232,7 @@ describe('extend', () => {
config.schema.validate({
loggers: [
{
context: 'plugins',
name: 'plugins',
level: 'warn',
},
],
@ -243,7 +243,7 @@ describe('extend', () => {
config.schema.validate({
loggers: [
{
context: 'plugins.pid',
name: 'plugins.pid',
level: 'trace',
},
],
@ -258,7 +258,7 @@ describe('extend', () => {
config.schema.validate({
loggers: [
{
context: 'plugins',
name: 'plugins',
level: 'warn',
},
],
@ -270,7 +270,7 @@ describe('extend', () => {
loggers: [
{
appenders: ['console'],
context: 'plugins',
name: 'plugins',
level: 'trace',
},
],
@ -279,7 +279,7 @@ describe('extend', () => {
expect(mergedConfigValue.loggers.get('plugins')).toEqual({
appenders: ['console'],
context: 'plugins',
name: 'plugins',
level: 'trace',
});
});

View file

@ -51,7 +51,7 @@ const levelSchema = schema.oneOf(
*/
export const loggerSchema = schema.object({
appenders: schema.arrayOf(schema.string(), { defaultValue: [] }),
context: schema.string(),
name: schema.string(),
level: levelSchema,
});
@ -148,15 +148,15 @@ export class LoggingConfig {
[
'default',
{
kind: 'console',
layout: { kind: 'pattern', highlight: true },
type: 'console',
layout: { type: 'pattern', highlight: true },
} as AppenderConfigType,
],
[
'console',
{
kind: 'console',
layout: { kind: 'pattern', highlight: true },
type: 'console',
layout: { type: 'pattern', highlight: true },
} as AppenderConfigType,
],
]);
@ -182,8 +182,8 @@ export class LoggingConfig {
public extend(contextConfig: LoggerContextConfigType) {
// Use a Map to de-dupe any loggers for the same context. contextConfig overrides existing config.
const mergedLoggers = new Map<string, LoggerConfigType>([
...this.configType.loggers.map((l) => [l.context, l] as [string, LoggerConfigType]),
...contextConfig.loggers.map((l) => [l.context, l] as [string, LoggerConfigType]),
...this.configType.loggers.map((l) => [l.name, l] as [string, LoggerConfigType]),
...contextConfig.loggers.map((l) => [l.name, l] as [string, LoggerConfigType]),
]);
const mergedConfig: LoggingConfigType = {
@ -204,13 +204,10 @@ export class LoggingConfig {
private fillLoggersConfig(loggingConfig: LoggingConfigType) {
// Include `root` logger into common logger list so that it can easily be a part
// of the logger hierarchy and put all the loggers in map for easier retrieval.
const loggers = [
{ context: ROOT_CONTEXT_NAME, ...loggingConfig.root },
...loggingConfig.loggers,
];
const loggers = [{ name: ROOT_CONTEXT_NAME, ...loggingConfig.root }, ...loggingConfig.loggers];
const loggerConfigByContext = new Map(
loggers.map((loggerConfig) => toTuple(loggerConfig.context, loggerConfig))
loggers.map((loggerConfig) => toTuple(loggerConfig.name, loggerConfig))
);
for (const [loggerContext, loggerConfig] of loggerConfigByContext) {
@ -247,7 +244,7 @@ function getAppenders(
loggerConfig: LoggerConfigType,
loggerConfigByContext: Map<string, LoggerConfigType>
) {
let currentContext = loggerConfig.context;
let currentContext = loggerConfig.name;
let appenders = loggerConfig.appenders;
while (appenders.length === 0) {

View file

@ -30,11 +30,11 @@ describe('LoggingService', () => {
it('forwards configuration changes to logging system', () => {
const config1: LoggerContextConfigType = {
appenders: new Map(),
loggers: [{ context: 'subcontext', appenders: ['console'], level: 'warn' }],
loggers: [{ name: 'subcontext', appenders: ['console'], level: 'warn' }],
};
const config2: LoggerContextConfigType = {
appenders: new Map(),
loggers: [{ context: 'subcontext', appenders: ['default'], level: 'all' }],
loggers: [{ name: 'subcontext', appenders: ['default'], level: 'all' }],
};
setup.configure(['test', 'context'], of(config1, config2));
@ -54,11 +54,11 @@ describe('LoggingService', () => {
const updates$ = new Subject<LoggerContextConfigType>();
const config1: LoggerContextConfigType = {
appenders: new Map(),
loggers: [{ context: 'subcontext', appenders: ['console'], level: 'warn' }],
loggers: [{ name: 'subcontext', appenders: ['console'], level: 'warn' }],
};
const config2: LoggerContextConfigType = {
appenders: new Map(),
loggers: [{ context: 'subcontext', appenders: ['default'], level: 'all' }],
loggers: [{ name: 'subcontext', appenders: ['default'], level: 'all' }],
};
setup.configure(['test', 'context'], updates$);
@ -78,7 +78,7 @@ describe('LoggingService', () => {
const updates$ = new Subject<LoggerContextConfigType>();
const config1: LoggerContextConfigType = {
appenders: new Map(),
loggers: [{ context: 'subcontext', appenders: ['console'], level: 'warn' }],
loggers: [{ name: 'subcontext', appenders: ['console'], level: 'warn' }],
};
setup.configure(['test', 'context'], updates$);

View file

@ -31,7 +31,7 @@ export interface LoggingServiceSetup {
* core.logging.configure(
* of({
* appenders: new Map(),
* loggers: [{ context: 'search', appenders: ['default'] }]
* loggers: [{ name: 'search', appenders: ['default'] }]
* })
* )
* ```

View file

@ -46,7 +46,7 @@ test('uses default memory buffer logger until config is provided', () => {
const logger = system.get('test', 'context');
logger.trace('trace message');
// We shouldn't create new buffer appender for another context.
// We shouldn't create new buffer appender for another context name.
const anotherLogger = system.get('test', 'context2');
anotherLogger.fatal('fatal message', { some: 'value' });
@ -69,7 +69,7 @@ test('flushes memory buffer logger and switches to real logger once config is pr
// Switch to console appender with `info` level, so that `trace` message won't go through.
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -102,12 +102,12 @@ test('appends records via multiple appenders.', async () => {
await system.upgrade(
config.schema.validate({
appenders: {
default: { kind: 'console', layout: { kind: 'pattern' } },
file: { kind: 'file', layout: { kind: 'pattern' }, path: 'path' },
default: { type: 'console', layout: { type: 'pattern' } },
file: { type: 'file', layout: { type: 'pattern' }, fileName: 'path' },
},
loggers: [
{ appenders: ['file'], context: 'tests', level: 'warn' },
{ context: 'tests.child', level: 'error' },
{ appenders: ['file'], name: 'tests', level: 'warn' },
{ name: 'tests.child', level: 'error' },
],
})
);
@ -121,10 +121,10 @@ test('appends records via multiple appenders.', async () => {
expect(mockStreamWrite.mock.calls[1][0]).toMatchSnapshot('file logs');
});
test('uses `root` logger if context is not specified.', async () => {
test('uses `root` logger if context name is not specified.', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'pattern' } } },
appenders: { default: { type: 'console', layout: { type: 'pattern' } } },
})
);
@ -137,7 +137,7 @@ test('uses `root` logger if context is not specified.', async () => {
test('`stop()` disposes all appenders.', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -156,7 +156,7 @@ test('asLoggerFactory() only allows to create new loggers.', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'all' },
})
);
@ -180,7 +180,7 @@ test('setContextConfig() updates config with relative contexts', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -189,10 +189,10 @@ test('setContextConfig() updates config with relative contexts', async () => {
appenders: new Map([
[
'custom',
{ kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } },
{ type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } },
],
]),
loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
});
testsLogger.warn('tests log to default!');
@ -235,7 +235,7 @@ test('setContextConfig() updates config for a root context', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -244,10 +244,10 @@ test('setContextConfig() updates config for a root context', async () => {
appenders: new Map([
[
'custom',
{ kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } },
{ type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } },
],
]),
loggers: [{ context: '', appenders: ['custom'], level: 'debug' }],
loggers: [{ name: '', appenders: ['custom'], level: 'debug' }],
});
testsLogger.warn('tests log to default!');
@ -273,21 +273,21 @@ test('setContextConfig() updates config for a root context', async () => {
);
});
test('custom context configs are applied on subsequent calls to update()', async () => {
test('custom context name configs are applied on subsequent calls to update()', async () => {
await system.setContextConfig(['tests', 'child'], {
appenders: new Map([
[
'custom',
{ kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } },
{ type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } },
],
]),
loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
});
// Calling upgrade after setContextConfig should not throw away the context-specific config
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -310,10 +310,10 @@ test('custom context configs are applied on subsequent calls to update()', async
);
});
test('subsequent calls to setContextConfig() for the same context override the previous config', async () => {
test('subsequent calls to setContextConfig() for the same context name override the previous config', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -322,10 +322,10 @@ test('subsequent calls to setContextConfig() for the same context override the p
appenders: new Map([
[
'custom',
{ kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } },
{ type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } },
],
]),
loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
});
// Call again, this time with level: 'warn' and a different pattern
@ -334,12 +334,12 @@ test('subsequent calls to setContextConfig() for the same context override the p
[
'custom',
{
kind: 'console',
layout: { kind: 'pattern', pattern: '[%level][%logger] second pattern! %message' },
type: 'console',
layout: { type: 'pattern', pattern: '[%level][%logger] second pattern! %message' },
},
],
]),
loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'warn' }],
loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'warn' }],
});
const logger = system.get('tests', 'child', 'grandchild');
@ -360,10 +360,10 @@ test('subsequent calls to setContextConfig() for the same context override the p
);
});
test('subsequent calls to setContextConfig() for the same context can disable the previous config', async () => {
test('subsequent calls to setContextConfig() for the same context name can disable the previous config', async () => {
await system.upgrade(
config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } },
appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' },
})
);
@ -372,10 +372,10 @@ test('subsequent calls to setContextConfig() for the same context can disable th
appenders: new Map([
[
'custom',
{ kind: 'console', layout: { kind: 'pattern', pattern: '[%level][%logger] %message' } },
{ type: 'console', layout: { type: 'pattern', pattern: '[%level][%logger] %message' } },
],
]),
loggers: [{ context: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
loggers: [{ name: 'grandchild', appenders: ['default', 'custom'], level: 'debug' }],
});
// Call again, this time no customizations (effectively disabling)

View file

@ -79,7 +79,7 @@ export class LoggingSystem implements LoggerFactory {
* loggingSystem.setContextConfig(
* ['plugins', 'data'],
* {
* loggers: [{ context: 'search', appenders: ['default'] }]
* loggers: [{ name: 'search', appenders: ['default'] }]
* }
* )
* ```
@ -95,9 +95,7 @@ export class LoggingSystem implements LoggerFactory {
// Automatically prepend the base context to the logger sub-contexts
loggers: contextConfig.loggers.map((l) => ({
...l,
context: LoggingConfig.getLoggerContext(
l.context.length > 0 ? [context, l.context] : [context]
),
name: LoggingConfig.getLoggerContext(l.name.length > 0 ? [context, l.name] : [context]),
})),
});

View file

@ -45,16 +45,16 @@ describe('migration v2', () => {
logging: {
appenders: {
file: {
kind: 'file',
path: join(__dirname, 'migration_test_kibana.log'),
type: 'file',
fileName: join(__dirname, 'migration_test_kibana.log'),
layout: {
kind: 'json',
type: 'json',
},
},
},
loggers: [
{
context: 'root',
name: 'root',
appenders: ['file'],
},
],

View file

@ -47,16 +47,16 @@ describe.skip('migration from 7.7.2-xpack with 100k objects', () => {
logging: {
appenders: {
file: {
kind: 'file',
path: join(__dirname, 'migration_test_kibana.log'),
type: 'file',
fileName: join(__dirname, 'migration_test_kibana.log'),
layout: {
kind: 'json',
type: 'json',
},
},
},
loggers: [
{
context: 'root',
name: 'root',
appenders: ['file'],
},
],

View file

@ -76,9 +76,9 @@ describe('#setup', () => {
config: {
enabled: true,
appender: {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
},
},
},
@ -102,9 +102,9 @@ describe('#setup', () => {
config: {
enabled: true,
appender: {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
},
},
},
@ -251,9 +251,9 @@ describe('#createLoggingConfig', () => {
createLoggingConfig({
enabled: true,
appender: {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
},
},
})
@ -264,10 +264,10 @@ describe('#createLoggingConfig', () => {
Object {
"appenders": Object {
"auditTrailAppender": Object {
"kind": "console",
"layout": Object {
"kind": "pattern",
"type": "pattern",
},
"type": "console",
},
},
"loggers": Array [
@ -275,8 +275,8 @@ describe('#createLoggingConfig', () => {
"appenders": Array [
"auditTrailAppender",
],
"context": "audit.ecs",
"level": "info",
"name": "audit.ecs",
},
],
}
@ -293,9 +293,9 @@ describe('#createLoggingConfig', () => {
createLoggingConfig({
enabled: false,
appender: {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
},
},
})
@ -331,9 +331,9 @@ describe('#createLoggingConfig', () => {
createLoggingConfig({
enabled: true,
appender: {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
},
},
})

View file

@ -224,16 +224,16 @@ export const createLoggingConfig = (config: ConfigType['audit']) =>
map<Pick<SecurityLicenseFeatures, 'allowAuditLogging'>, LoggerContextConfigInput>((features) => ({
appenders: {
auditTrailAppender: config.appender ?? {
kind: 'console',
type: 'console',
layout: {
kind: 'pattern',
type: 'pattern',
highlight: true,
},
},
},
loggers: [
{
context: 'audit.ecs',
name: 'audit.ecs',
level: config.enabled && config.appender && features.allowAuditLogging ? 'info' : 'off',
appenders: ['auditTrailAppender'],
},

View file

@ -1558,21 +1558,21 @@ describe('createConfig()', () => {
ConfigSchema.validate({
audit: {
appender: {
kind: 'file',
path: '/path/to/file.txt',
type: 'file',
fileName: '/path/to/file.txt',
layout: {
kind: 'json',
type: 'json',
},
},
},
}).audit.appender
).toMatchInlineSnapshot(`
Object {
"kind": "file",
"fileName": "/path/to/file.txt",
"layout": Object {
"kind": "json",
"type": "json",
},
"path": "/path/to/file.txt",
"type": "file",
}
`);
});
@ -1583,12 +1583,12 @@ describe('createConfig()', () => {
audit: {
// no layout configured
appender: {
kind: 'file',
type: 'file',
path: '/path/to/file.txt',
},
},
})
).toThrow('[audit.appender.2.kind]: expected value to equal [legacy-appender]');
).toThrow('[audit.appender.2.type]: expected value to equal [legacy-appender]');
});
it('rejects an ignore_filter when no appender is configured', () => {

View file

@ -52,6 +52,117 @@ describe('Config Deprecations', () => {
`);
});
it('renames audit.appender.kind to audit.appender.type', () => {
const config = {
xpack: {
security: {
audit: {
appender: {
kind: 'console',
},
},
},
},
};
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
expect(migrated.xpack.security.audit.appender.kind).not.toBeDefined();
expect(migrated.xpack.security.audit.appender.type).toEqual('console');
expect(messages).toMatchInlineSnapshot(`
Array [
"\\"xpack.security.audit.appender.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.type\\"",
]
`);
});
it('renames audit.appender.layout.kind to audit.appender.layout.type', () => {
const config = {
xpack: {
security: {
audit: {
appender: {
layout: { kind: 'pattern' },
},
},
},
},
};
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
expect(migrated.xpack.security.audit.appender.layout.kind).not.toBeDefined();
expect(migrated.xpack.security.audit.appender.layout.type).toEqual('pattern');
expect(messages).toMatchInlineSnapshot(`
Array [
"\\"xpack.security.audit.appender.layout.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.layout.type\\"",
]
`);
});
it('renames audit.appender.policy.kind to audit.appender.policy.type', () => {
const config = {
xpack: {
security: {
audit: {
appender: {
policy: { kind: 'time-interval' },
},
},
},
},
};
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
expect(migrated.xpack.security.audit.appender.policy.kind).not.toBeDefined();
expect(migrated.xpack.security.audit.appender.policy.type).toEqual('time-interval');
expect(messages).toMatchInlineSnapshot(`
Array [
"\\"xpack.security.audit.appender.policy.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.policy.type\\"",
]
`);
});
it('renames audit.appender.strategy.kind to audit.appender.strategy.type', () => {
const config = {
xpack: {
security: {
audit: {
appender: {
strategy: { kind: 'numeric' },
},
},
},
},
};
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
expect(migrated.xpack.security.audit.appender.strategy.kind).not.toBeDefined();
expect(migrated.xpack.security.audit.appender.strategy.type).toEqual('numeric');
expect(messages).toMatchInlineSnapshot(`
Array [
"\\"xpack.security.audit.appender.strategy.kind\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.strategy.type\\"",
]
`);
});
it('renames audit.appender.path to audit.appender.fileName', () => {
const config = {
xpack: {
security: {
audit: {
appender: {
type: 'file',
path: './audit.log',
},
},
},
},
};
const { messages, migrated } = applyConfigDeprecations(cloneDeep(config));
expect(migrated.xpack.security.audit.appender.path).not.toBeDefined();
expect(migrated.xpack.security.audit.appender.fileName).toEqual('./audit.log');
expect(messages).toMatchInlineSnapshot(`
Array [
"\\"xpack.security.audit.appender.path\\" is deprecated and has been replaced by \\"xpack.security.audit.appender.fileName\\"",
]
`);
});
it(`warns that 'authorization.legacyFallback.enabled' is unused`, () => {
const config = {
xpack: {

View file

@ -12,6 +12,13 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
unused,
}) => [
rename('sessionTimeout', 'session.idleTimeout'),
rename('audit.appender.kind', 'audit.appender.type'),
rename('audit.appender.layout.kind', 'audit.appender.layout.type'),
rename('audit.appender.policy.kind', 'audit.appender.policy.type'),
rename('audit.appender.strategy.kind', 'audit.appender.strategy.type'),
rename('audit.appender.path', 'audit.appender.fileName'),
unused('authorization.legacyFallback.enabled'),
unused('authc.saml.maxRedirectURLSize'),
// Deprecation warning for the old array-based format of `xpack.security.authc.providers`.

View file

@ -29,9 +29,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
...xPackAPITestsConfig.get('kbnTestServer.serverArgs'),
`--plugin-path=${auditLogPlugin}`,
'--xpack.security.audit.enabled=true',
'--xpack.security.audit.appender.kind=file',
`--xpack.security.audit.appender.path=${auditLogPath}`,
'--xpack.security.audit.appender.layout.kind=json',
'--xpack.security.audit.appender.type=file',
`--xpack.security.audit.appender.fileName=${auditLogPath}`,
'--xpack.security.audit.appender.layout.type=json',
],
},
};