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( core.logging.configure(
of({ of({
appenders: new Map(), 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] [source,yaml]
---------------------------------------- ----------------------------------------
xpack.security.audit.appender: xpack.security.audit.appender:
kind: rolling-file type: rolling-file
path: ./audit.log fileName: ./audit.log
policy: policy:
kind: time-interval type: time-interval
interval: 24h <1> interval: 24h <1>
strategy: strategy:
kind: numeric type: numeric
max: 10 <2> max: 10 <2>
layout: layout:
kind: json type: json
---------------------------------------- ----------------------------------------
<1> Rotates log files every 24 hours. <1> Rotates log files every 24 hours.
<2> Keeps maximum of 10 log files before deleting older ones. <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`. | 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. 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`. | Required. Specifies how audit logs should be formatted. Allowed values are `json` or `pattern`.
Refer to <<audit-logging-pattern-layout>> for layout specific settings. 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*<"] [cols="2*<"]
|====== |======
| `xpack.security.audit.appender.path` | `xpack.security.audit.appender.fileName`
| Required. Full file path the log file should be written to. | 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*<"] [cols="2*<"]
|====== |======
| `xpack.security.audit.appender.path` | `xpack.security.audit.appender.fileName`
| Required. Full file path the log file should be written to. | 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`. | 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. 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` | Specifies how the rollover should occur. Only allowed value is currently `numeric`. *Default:* `numeric`
Refer to <<audit-logging-numeric-strategy>> for strategy specific settings. 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 { Object {
"appenders": Object { "appenders": Object {
"default": Object { "default": Object {
"kind": "legacy-appender",
"legacyLoggingConfig": Object { "legacyLoggingConfig": Object {
"silent": true, "silent": true,
}, },
"type": "legacy-appender",
}, },
}, },
"loggers": undefined, "loggers": undefined,
@ -85,12 +85,12 @@ exports[`#get correctly handles verbose file logging config with json format. 1`
Object { Object {
"appenders": Object { "appenders": Object {
"default": Object { "default": Object {
"kind": "legacy-appender",
"legacyLoggingConfig": Object { "legacyLoggingConfig": Object {
"dest": "/some/path.log", "dest": "/some/path.log",
"json": true, "json": true,
"verbose": true, "verbose": true,
}, },
"type": "legacy-appender",
}, },
}, },
"loggers": undefined, "loggers": undefined,

View file

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

View file

@ -226,7 +226,7 @@ export class CoreUsageDataService implements CoreService<CoreUsageDataSetup, Cor
logging: { logging: {
appendersTypesUsed: Array.from( appendersTypesUsed: Array.from(
Array.from(this.loggingConfig?.appenders.values() ?? []) 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() .values()
), ),
loggersConfiguredCount: this.loggingConfig?.loggers.length ?? 0, loggersConfiguredCount: this.loggingConfig?.loggers.length ?? 0,

View file

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

View file

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

View file

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

View file

@ -12,7 +12,7 @@ import { DisposableAppender, LogRecord } from '@kbn/logging';
import { LegacyVars } from '../../types'; import { LegacyVars } from '../../types';
export interface LegacyAppenderConfig { export interface LegacyAppenderConfig {
kind: 'legacy-appender'; type: 'legacy-appender';
legacyLoggingConfig?: any; legacyLoggingConfig?: any;
} }
@ -22,7 +22,7 @@ export interface LegacyAppenderConfig {
*/ */
export class LegacyAppender implements DisposableAppender { export class LegacyAppender implements DisposableAppender {
public static configSchema = schema.object({ public static configSchema = schema.object({
kind: schema.literal('legacy-appender'), type: schema.literal('legacy-appender'),
legacyLoggingConfig: schema.any(), 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 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. 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). __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 ## 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 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 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 that resides at the top of the logger hierarchy. This logger always exists and logger with `root` context name that resides at the top of the logger hierarchy. This logger always exists and
fully configured. 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. 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 __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 we __don't support__ so called _appender additivity_ when log messages are forwarded to _every_ distinct appender within
ancestor chain including `root`. 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 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 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 ## Layouts
@ -129,7 +129,7 @@ Example of `%date` output:
Outputs the process ID. Outputs the process ID.
### JSON layout ### 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. text and any other metadata that may be associated with the log message itself.
## Appenders ## Appenders
@ -153,15 +153,15 @@ This policy will rotate the file when it reaches a predetermined size.
logging: logging:
appenders: appenders:
rolling-file: rolling-file:
kind: rolling-file type: rolling-file
path: /var/logs/kibana.log fileName: /var/logs/kibana.log
policy: policy:
kind: size-limit type: size-limit
size: 50mb size: 50mb
strategy: strategy:
//... //...
layout: layout:
kind: pattern type: pattern
``` ```
The options are: The options are:
@ -180,16 +180,16 @@ This policy will rotate the file every given interval of time.
logging: logging:
appenders: appenders:
rolling-file: rolling-file:
kind: rolling-file type: rolling-file
path: /var/logs/kibana.log fileName: /var/logs/kibana.log
policy: policy:
kind: time-interval type: time-interval
interval: 10s interval: 10s
modulate: true modulate: true
strategy: strategy:
//... //...
layout: layout:
kind: pattern type: pattern
``` ```
The options are: The options are:
@ -225,16 +225,16 @@ and will retains a fixed amount of rolled files.
logging: logging:
appenders: appenders:
rolling-file: rolling-file:
kind: rolling-file type: rolling-file
path: /var/logs/kibana.log fileName: /var/logs/kibana.log
policy: policy:
// ... // ...
strategy: strategy:
kind: numeric type: numeric
pattern: '-%i' pattern: '-%i'
max: 2 max: 2
layout: layout:
kind: pattern type: pattern
``` ```
For example, with this configuration: 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 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. 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. will be `/var/logs/kibana-1.log`, `/var/logs/kibana-2.log`, and so on.
The default value is `-%i` The default value is `-%i`
@ -278,49 +278,49 @@ Here is the configuration example that can be used to configure _loggers_, _appe
logging: logging:
appenders: appenders:
console: console:
kind: console type: console
layout: layout:
kind: pattern type: pattern
highlight: true highlight: true
file: file:
kind: file type: file
path: /var/log/kibana.log fileName: /var/log/kibana.log
layout: layout:
kind: pattern type: pattern
custom: custom:
kind: console type: console
layout: layout:
kind: pattern type: pattern
pattern: "[%date][%level] %message" pattern: "[%date][%level] %message"
json-file-appender: json-file-appender:
kind: file type: file
path: /var/log/kibana-json.log fileName: /var/log/kibana-json.log
root: root:
appenders: [console, file] appenders: [console, file]
level: error level: error
loggers: loggers:
- context: plugins - name: plugins
appenders: [custom] appenders: [custom]
level: warn level: warn
- context: plugins.myPlugin - name: plugins.myPlugin
level: info level: info
- context: server - name: server
level: fatal level: fatal
- context: optimize - name: optimize
appenders: [console] appenders: [console]
- context: telemetry - name: telemetry
level: all level: all
appenders: [json-file-appender] appenders: [json-file-appender]
- context: metrics.ops - name: metrics.ops
level: debug level: debug
appenders: [console] appenders: [console]
``` ```
Here is what we get with the config above: Here is what we get with the config above:
| Context | Appenders | Level | | Context name | Appenders | Level |
| ---------------- |:------------------------:| -----:| | ---------------- |:------------------------:| -----:|
| root | console, file | error | | root | console, file | error |
| plugins | custom | warn | | plugins | custom | warn |
@ -331,7 +331,7 @@ Here is what we get with the config above:
| metrics.ops | console | debug | | 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 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. 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
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. different log level.
```typescript ```typescript
@ -409,7 +409,7 @@ loggerWithNestedContext.trace('Message with `trace` log level.');
loggerWithNestedContext.debug('Message with `debug` 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 ```bash
[2017-07-25T11:54:41.639-07:00][TRACE][server] Message with `trace` log level. [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. [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. [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 ```bash
[2017-07-25T11:54:41.639-07:00][WARN ][server] Message with `warn` log level. [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. [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. 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 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. 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. `root` context anymore and not forwarded to the legacy logging service.
#### logging.dest #### logging.dest
@ -442,21 +442,21 @@ define a custom one.
```yaml ```yaml
logging: logging:
loggers: loggers:
- context: plugins.myPlugin - name: plugins.myPlugin
appenders: [console] 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 ```yaml
logging: logging:
appenders: appenders:
file: file:
kind: file type: file
path: /var/log/kibana.log fileName: /var/log/kibana.log
layout: layout:
kind: pattern type: pattern
loggers: loggers:
- context: plugins.myPlugin - name: plugins.myPlugin
appenders: [file] appenders: [file]
``` ```
#### logging.json #### 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). with adjusting minimum required [logging level](#log-level).
```yaml ```yaml
loggers: loggers:
- context: plugins.myPlugin - name: plugins.myPlugin
appenders: [console] appenders: [console]
level: error level: error
# or for all output # or for all output
@ -494,32 +494,32 @@ to [specify timezone](#date) for `layout: pattern`. Defaults to host timezone wh
logging: logging:
appenders: appenders:
custom-console: custom-console:
kind: console type: console
layout: layout:
kind: pattern type: pattern
highlight: true highlight: true
pattern: "[%level] [%date{ISO8601_TZ}{America/Los_Angeles}][%logger] %message" pattern: "[%level] [%date{ISO8601_TZ}{America/Los_Angeles}][%logger] %message"
``` ```
#### logging.events #### 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. **`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`: and you can enable them by adjusting the minimum required [logging level](#log-level) to `debug`:
```yaml ```yaml
loggers: loggers:
- context: metrics.ops - name: metrics.ops
appenders: [console] appenders: [console]
level: debug level: debug
``` ```
**`logging.events.request` and `logging.events.response`** provide logs for each request handled **`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`: and you can enable them by adjusting the minimum required [logging level](#log-level) to `debug`:
```yaml ```yaml
loggers: loggers:
- context: http.server.response - name: http.server.response
appenders: [console] appenders: [console]
level: debug level: debug
``` ```
@ -532,7 +532,7 @@ TBD
| Parameter | Platform log record in **pattern** format | Legacy Platform log record **text** format | | 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` | | @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']` | | level | `DEBUG` | `['debug']` |
| meta | stringified JSON object `{"to": "v8"}` | N/A | | meta | stringified JSON object `{"to": "v8"}` | N/A |
| pid | can be configured as `%pid` | 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 | | 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` | | @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']` | | context name | `log.logger: parent.child` | `tags: ['parent', 'child']` |
| level | `level: DEBUG` | `tags: ['debug']` | | level | `log.level: DEBUG` | `tags: ['debug']` |
| meta | separate property `"meta": {"to": "v8"}` | merged in log record `{... "to": "v8"}` | | 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` | | type | N/A | `type: log` |
| error | `{ message, name, stack }` | `{ message, name, stack, code, signal }` | | 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 [
Array [ Array [
"[2012-01-31T03:33:22.011-05:00][INFO ][root] This message goes to a root context.", "[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'); const { schema } = require('@kbn/config-schema');
return { return {
Layouts: { Layouts: {
configSchema: schema.object({ kind: schema.literal('mock') }), configSchema: schema.object({ type: schema.literal('mock') }),
create: mockCreateLayout, create: mockCreateLayout,
}, },
}; };

View file

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

View file

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

View file

@ -12,7 +12,7 @@ jest.mock('../../layouts/layouts', () => {
return { return {
Layouts: { Layouts: {
configSchema: schema.object({ 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.', () => { test('`configSchema` creates correct schema.', () => {
const appenderSchema = ConsoleAppender.configSchema; const appenderSchema = ConsoleAppender.configSchema;
const validConfig = { kind: 'console', layout: { kind: 'mock' } }; const validConfig = { type: 'console', layout: { type: 'mock' } };
expect(appenderSchema.validate(validConfig)).toEqual({ expect(appenderSchema.validate(validConfig)).toEqual({
kind: 'console', type: 'console',
layout: { kind: 'mock' }, layout: { type: 'mock' },
}); });
const wrongConfig1 = { kind: 'not-console', layout: { kind: 'mock' } }; const wrongConfig1 = { type: 'not-console', layout: { type: 'mock' } };
expect(() => appenderSchema.validate(wrongConfig1)).toThrow(); 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(); expect(() => appenderSchema.validate(wrongConfig2)).toThrow();
}); });

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -63,7 +63,7 @@ const records: LogRecord[] = [
test('`createConfigSchema()` creates correct schema.', () => { test('`createConfigSchema()` creates correct schema.', () => {
const layoutSchema = JsonLayout.configSchema; 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.', () => { test('`format()` correctly formats record.', () => {

View file

@ -14,12 +14,12 @@ import { LogRecord, Layout } from '@kbn/logging';
const { literal, object } = schema; const { literal, object } = schema;
const jsonLayoutSchema = object({ const jsonLayoutSchema = object({
kind: literal('json'), type: literal('json'),
}); });
/** @internal */ /** @internal */
export interface JsonLayoutConfigType { 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.', () => { test('`configSchema` creates correct schema for `pattern` layout.', () => {
const layoutsSchema = Layouts.configSchema; const layoutsSchema = Layouts.configSchema;
const validConfigWithOptional = { kind: 'pattern' }; const validConfigWithOptional = { type: 'pattern' };
expect(layoutsSchema.validate(validConfigWithOptional)).toEqual({ expect(layoutsSchema.validate(validConfigWithOptional)).toEqual({
highlight: undefined, highlight: undefined,
kind: 'pattern', type: 'pattern',
pattern: undefined, pattern: undefined,
}); });
const validConfig = { const validConfig = {
highlight: true, highlight: true,
kind: 'pattern', type: 'pattern',
pattern: '%message', pattern: '%message',
}; };
expect(layoutsSchema.validate(validConfig)).toEqual({ expect(layoutsSchema.validate(validConfig)).toEqual({
highlight: true, highlight: true,
kind: 'pattern', type: 'pattern',
pattern: '%message', pattern: '%message',
}); });
const wrongConfig2 = { kind: 'pattern', pattern: 1 }; const wrongConfig2 = { type: 'pattern', pattern: 1 };
expect(() => layoutsSchema.validate(wrongConfig2)).toThrow(); expect(() => layoutsSchema.validate(wrongConfig2)).toThrow();
}); });
test('`createConfigSchema()` creates correct schema for `json` layout.', () => { test('`createConfigSchema()` creates correct schema for `json` layout.', () => {
const layoutsSchema = Layouts.configSchema; const layoutsSchema = Layouts.configSchema;
const validConfig = { kind: 'json' }; const validConfig = { type: 'json' };
expect(layoutsSchema.validate(validConfig)).toEqual({ kind: 'json' }); expect(layoutsSchema.validate(validConfig)).toEqual({ type: 'json' });
}); });
test('`create()` creates correct layout.', () => { test('`create()` creates correct layout.', () => {
const patternLayout = Layouts.create({ const patternLayout = Layouts.create({
highlight: false, highlight: false,
kind: 'pattern', type: 'pattern',
pattern: '[%date][%level][%logger] %message', pattern: '[%date][%level][%logger] %message',
}); });
expect(patternLayout).toBeInstanceOf(PatternLayout); expect(patternLayout).toBeInstanceOf(PatternLayout);
const jsonLayout = Layouts.create({ kind: 'json' }); const jsonLayout = Layouts.create({ type: 'json' });
expect(jsonLayout).toBeInstanceOf(JsonLayout); expect(jsonLayout).toBeInstanceOf(JsonLayout);
}); });

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -31,7 +31,7 @@ export interface LoggingServiceSetup {
* core.logging.configure( * core.logging.configure(
* of({ * of({
* appenders: new Map(), * 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'); const logger = system.get('test', 'context');
logger.trace('trace message'); 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'); const anotherLogger = system.get('test', 'context2');
anotherLogger.fatal('fatal message', { some: 'value' }); 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. // Switch to console appender with `info` level, so that `trace` message won't go through.
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, root: { level: 'info' },
}) })
); );
@ -102,12 +102,12 @@ test('appends records via multiple appenders.', async () => {
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { appenders: {
default: { kind: 'console', layout: { kind: 'pattern' } }, default: { type: 'console', layout: { type: 'pattern' } },
file: { kind: 'file', layout: { kind: 'pattern' }, path: 'path' }, file: { type: 'file', layout: { type: 'pattern' }, fileName: 'path' },
}, },
loggers: [ loggers: [
{ appenders: ['file'], context: 'tests', level: 'warn' }, { appenders: ['file'], name: 'tests', level: 'warn' },
{ context: 'tests.child', level: 'error' }, { 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'); 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( await system.upgrade(
config.schema.validate({ 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 () => { test('`stop()` disposes all appenders.', async () => {
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, root: { level: 'info' },
}) })
); );
@ -156,7 +156,7 @@ test('asLoggerFactory() only allows to create new loggers.', async () => {
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'all' }, root: { level: 'all' },
}) })
); );
@ -180,7 +180,7 @@ test('setContextConfig() updates config with relative contexts', async () => {
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, root: { level: 'info' },
}) })
); );
@ -189,10 +189,10 @@ test('setContextConfig() updates config with relative contexts', async () => {
appenders: new Map([ appenders: new Map([
[ [
'custom', '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!'); testsLogger.warn('tests log to default!');
@ -235,7 +235,7 @@ test('setContextConfig() updates config for a root context', async () => {
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, root: { level: 'info' },
}) })
); );
@ -244,10 +244,10 @@ test('setContextConfig() updates config for a root context', async () => {
appenders: new Map([ appenders: new Map([
[ [
'custom', '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!'); 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'], { await system.setContextConfig(['tests', 'child'], {
appenders: new Map([ appenders: new Map([
[ [
'custom', '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 // Calling upgrade after setContextConfig should not throw away the context-specific config
await system.upgrade( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, 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( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, root: { level: 'info' },
}) })
); );
@ -322,10 +322,10 @@ test('subsequent calls to setContextConfig() for the same context override the p
appenders: new Map([ appenders: new Map([
[ [
'custom', '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 // 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', 'custom',
{ {
kind: 'console', type: 'console',
layout: { kind: 'pattern', pattern: '[%level][%logger] second pattern! %message' }, 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'); 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( await system.upgrade(
config.schema.validate({ config.schema.validate({
appenders: { default: { kind: 'console', layout: { kind: 'json' } } }, appenders: { default: { type: 'console', layout: { type: 'json' } } },
root: { level: 'info' }, root: { level: 'info' },
}) })
); );
@ -372,10 +372,10 @@ test('subsequent calls to setContextConfig() for the same context can disable th
appenders: new Map([ appenders: new Map([
[ [
'custom', '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) // Call again, this time no customizations (effectively disabling)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1558,21 +1558,21 @@ describe('createConfig()', () => {
ConfigSchema.validate({ ConfigSchema.validate({
audit: { audit: {
appender: { appender: {
kind: 'file', type: 'file',
path: '/path/to/file.txt', fileName: '/path/to/file.txt',
layout: { layout: {
kind: 'json', type: 'json',
}, },
}, },
}, },
}).audit.appender }).audit.appender
).toMatchInlineSnapshot(` ).toMatchInlineSnapshot(`
Object { Object {
"kind": "file", "fileName": "/path/to/file.txt",
"layout": Object { "layout": Object {
"kind": "json", "type": "json",
}, },
"path": "/path/to/file.txt", "type": "file",
} }
`); `);
}); });
@ -1583,12 +1583,12 @@ describe('createConfig()', () => {
audit: { audit: {
// no layout configured // no layout configured
appender: { appender: {
kind: 'file', type: 'file',
path: '/path/to/file.txt', 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', () => { 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`, () => { it(`warns that 'authorization.legacyFallback.enabled' is unused`, () => {
const config = { const config = {
xpack: { xpack: {

View file

@ -12,6 +12,13 @@ export const securityConfigDeprecationProvider: ConfigDeprecationProvider = ({
unused, unused,
}) => [ }) => [
rename('sessionTimeout', 'session.idleTimeout'), 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('authorization.legacyFallback.enabled'),
unused('authc.saml.maxRedirectURLSize'), unused('authc.saml.maxRedirectURLSize'),
// Deprecation warning for the old array-based format of `xpack.security.authc.providers`. // 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'), ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'),
`--plugin-path=${auditLogPlugin}`, `--plugin-path=${auditLogPlugin}`,
'--xpack.security.audit.enabled=true', '--xpack.security.audit.enabled=true',
'--xpack.security.audit.appender.kind=file', '--xpack.security.audit.appender.type=file',
`--xpack.security.audit.appender.path=${auditLogPath}`, `--xpack.security.audit.appender.fileName=${auditLogPath}`,
'--xpack.security.audit.appender.layout.kind=json', '--xpack.security.audit.appender.layout.type=json',
], ],
}, },
}; };