1# Logging 2 3- [Loggers, Appenders and Layouts](#loggers-appenders-and-layouts) 4- [Logger hierarchy](#logger-hierarchy) 5- [Log level](#log-level) 6- [Layouts](#layouts) 7 - [Pattern layout](#pattern-layout) 8 - [JSON layout](#json-layout) 9- [Configuration](#configuration) 10- [Usage](#usage) 11- [Logging config migration](#logging-config-migration) 12- [Log record format changes](#log-record-format-changes) 13 14The way logging works in OpenSearch Dashboards is inspired by `log4j 2` logging framework used by [OpenSearch](https://www.opensearch.org/guide/en/elasticsearch/reference/current/settings.html#logging). 15The main idea is to have consistent logging behaviour (configuration, log format etc.) across the entire OpenSearch Stack 16where possible. 17 18## Loggers, Appenders and Layouts 19 20OpenSearch Dashboards logging system has three main components: _loggers_, _appenders_ and _layouts_. These components allow us to log 21messages according to message type and level, and to control how these messages are formatted and where the final logs 22will be displayed or stored. 23 24**Loggers** define what logging settings should be applied at the particular context. 25 26**Appenders** define where log messages are displayed (eg. stdout or console) and stored (eg. file on the disk). 27 28**Layouts** define how log messages are formatted and what type of information they include. 29 30## Logger hierarchy 31 32Every logger has its unique name or context that follows hierarchical naming rule. The logger is considered to be an 33ancestor of another logger if its name followed by a `.` is a prefix of the descendant logger name. For example logger 34with `a.b` context is an ancestor of logger with `a.b.c` context. All top-level loggers are descendants of special 35logger with `root` context that resides at the top of the logger hierarchy. This logger always exists and 36fully configured. 37 38Developer can configure _log level_ and _appenders_ that should be used within particular context. If logger configuration 39specifies only _log level_ then _appenders_ configuration will be inherited from the ancestor logger. 40 41**Note:** in the current implementation log messages are only forwarded to appenders configured for a particular logger 42context or to appenders of the closest ancestor if current logger doesn't have any appenders configured. That means that 43we **don't support** so called _appender additivity_ when log messages are forwarded to _every_ distinct appender within 44ancestor chain including `root`. 45 46## Log level 47 48Currently we support the following log levels: _all_, _fatal_, _error_, _warn_, _info_, _debug_, _trace_, _off_. 49Levels are ordered, so _all_ > _fatal_ > _error_ > _warn_ > _info_ > _debug_ > _trace_ > _off_. 50A log record is being logged by the logger if its level is higher than or equal to the level of its logger. Otherwise, 51the log record is ignored. 52 53The _all_ and _off_ levels can be used only in configuration and are just handy shortcuts that allow developer to log every 54log record or disable logging entirely for the specific context. 55 56## Layouts 57 58Every appender should know exactly how to format log messages before they are written to the console or file on the disk. 59This behaviour is controlled by the layouts and configured through `appender.layout` configuration property for every 60custom appender (see examples in [Configuration](#configuration)). Currently we don't define any default layout for the 61custom appenders, so one should always make the choice explicitly. 62 63There are two types of layout supported at the moment: `pattern` and `json`. 64 65### Pattern layout 66 67With `pattern` layout it's possible to define a string pattern with special placeholders `%conversion_pattern` (see the table below) that 68will be replaced with data from the actual log message. By default the following pattern is used: 69`[%date][%level][%logger]%meta %message`. Also `highlight` option can be enabled for `pattern` layout so that 70some parts of the log message are highlighted with different colors that may be quite handy if log messages are forwarded 71to the terminal with color support. 72`pattern` layout uses a sub-set of [log4j2 pattern syntax](https://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout) 73and **doesn't implement** all `log4j2` capabilities. The conversions that are provided out of the box are: 74 75#### level 76 77Outputs the [level](#log-level) of the logging event. 78Example of `%level` output: 79 80```bash 81TRACE 82DEBUG 83INFO 84``` 85 86##### logger 87 88Outputs the name of the logger that published the logging event. 89Example of `%logger` output: 90 91```bash 92server 93server.http 94server.http.OpenSearchDashboards 95``` 96 97#### message 98 99Outputs the application supplied message associated with the logging event. 100 101#### meta 102 103Outputs the entries of `meta` object data in **json** format, if one is present in the event. 104Example of `%meta` output: 105 106```bash 107// Meta{from: 'v7', to: 'v8'} 108'{"from":"v7","to":"v8"}' 109// Meta empty object 110'{}' 111// no Meta provided 112'' 113``` 114 115##### date 116 117Outputs the date of the logging event. The date conversion specifier may be followed by a set of braces containing a name of predefined date format and canonical timezone name. 118Timezone name is expected to be one from [TZ database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) 119Example of `%date` output: 120 121| Conversion pattern | Example | 122| ---------------------------------------- | ----------------------------------------------------------- | 123| `%date` | `2012-02-01T14:30:22.011Z` uses `ISO8601` format by default | 124| `%date{ISO8601}` | `2012-02-01T14:30:22.011Z` | 125| `%date{ISO8601_TZ}` | `2012-02-01T09:30:22.011-05:00` `ISO8601` with timezone | 126| `%date{ISO8601_TZ}{America/Los_Angeles}` | `2012-02-01T06:30:22.011-08:00` | 127| `%date{ABSOLUTE}` | `09:30:22.011` | 128| `%date{ABSOLUTE}{America/Los_Angeles}` | `06:30:22.011` | 129| `%date{UNIX}` | `1328106622` | 130| `%date{UNIX_MILLIS}` | `1328106622011` | 131 132#### pid 133 134Outputs the process ID. 135 136### JSON layout 137 138With `json` layout log messages will be formatted as JSON strings that include timestamp, log level, context, message 139text and any other metadata that may be associated with the log message itself. 140 141## Configuration 142 143As any configuration in the platform, logging configuration is validated against the predefined schema and if there are 144any issues with it, OpenSearch Dashboards will fail to start with the detailed error message. 145 146Once the code acquired a logger instance it should not care about any runtime changes in the configuration that may 147happen: all changes will be applied to existing logger instances under the hood. 148 149Here is the configuration example that can be used to configure _loggers_, _appenders_ and _layouts_: 150 151```yaml 152logging: 153 appenders: 154 console: 155 kind: console 156 layout: 157 kind: pattern 158 highlight: true 159 file: 160 kind: file 161 path: /var/log/opensearch_dashboards.log 162 layout: 163 kind: pattern 164 custom: 165 kind: console 166 layout: 167 kind: pattern 168 pattern: '[%date][%level] %message' 169 json-file-appender: 170 kind: file 171 path: /var/log/opensearch-dashboards-json.log 172 173 root: 174 appenders: [console, file] 175 level: error 176 177 loggers: 178 - context: plugins 179 appenders: [custom] 180 level: warn 181 - context: plugins.myPlugin 182 level: info 183 - context: server 184 level: fatal 185 - context: optimize 186 appenders: [console] 187 - context: telemetry 188 level: all 189 appenders: [json-file-appender] 190``` 191 192Here is what we get with the config above: 193 194| Context | Appenders | Level | 195| ---------------- | :----------------: | ----: | 196| root | console, file | error | 197| plugins | custom | warn | 198| plugins.myPlugin | custom | info | 199| server | console, file | fatal | 200| optimize | console | error | 201| telemetry | json-file-appender | all | 202 203The `root` logger has a dedicated configuration node since this context is special and should always exist. By 204default `root` is configured with `info` level and `default` appender that is also always available. This is the 205configuration that all custom loggers will use unless they're re-configured explicitly. 206 207For example to see _all_ log messages that fall back on the `root` logger configuration, just add one line to the configuration: 208 209```yaml 210logging.root.level: all 211``` 212 213Or disable logging entirely with `off`: 214 215```yaml 216logging.root.level: off 217``` 218 219## Usage 220 221Usage is very straightforward, one should just get a logger for a specific context and use it to log messages with 222different log level. 223 224```typescript 225const logger = opensearchDashboards.logger.get('server'); 226 227logger.trace('Message with `trace` log level.'); 228logger.debug('Message with `debug` log level.'); 229logger.info('Message with `info` log level.'); 230logger.warn('Message with `warn` log level.'); 231logger.error('Message with `error` log level.'); 232logger.fatal('Message with `fatal` log level.'); 233 234const loggerWithNestedContext = opensearchDashboards.logger.get('server', 'http'); 235loggerWithNestedContext.trace('Message with `trace` log level.'); 236loggerWithNestedContext.debug('Message with `debug` log level.'); 237``` 238 239And assuming logger for `server` context with `console` appender and `trace` level was used, console output will look like this: 240 241```bash 242[2017-07-25T18:54:41.639Z][TRACE][server] Message with `trace` log level. 243[2017-07-25T18:54:41.639Z][DEBUG][server] Message with `debug` log level. 244[2017-07-25T18:54:41.639Z][INFO ][server] Message with `info` log level. 245[2017-07-25T18:54:41.639Z][WARN ][server] Message with `warn` log level. 246[2017-07-25T18:54:41.639Z][ERROR][server] Message with `error` log level. 247[2017-07-25T18:54:41.639Z][FATAL][server] Message with `fatal` log level. 248 249[2017-07-25T18:54:41.639Z][TRACE][server.http] Message with `trace` log level. 250[2017-07-25T18:54:41.639Z][DEBUG][server.http] Message with `debug` log level. 251``` 252 253The log will be less verbose with `warn` level for the `server` context: 254 255```bash 256[2017-07-25T18:54:41.639Z][WARN ][server] Message with `warn` log level. 257[2017-07-25T18:54:41.639Z][ERROR][server] Message with `error` log level. 258[2017-07-25T18:54:41.639Z][FATAL][server] Message with `fatal` log level. 259``` 260 261### Logging config migration 262 263Compatibility with the legacy logging system is assured until the end of the `v7` version. 264All log messages handled by `root` context are forwarded to the legacy logging service. If you re-write 265root appenders, make sure that it contains `default` appender to provide backward compatibility. 266**Note**: If you define an appender for a context, the log messages aren't handled by the 267`root` context anymore and not forwarded to the legacy logging service. 268 269#### logging.dest 270 271By default logs in _stdout_. With new OpenSearch Dashboards logging you can use pre-existing `console` appender or 272define a custom one. 273 274```yaml 275logging: 276 loggers: 277 - context: plugins.myPlugin 278 appenders: [console] 279``` 280 281Logs in a _file_ if given file path. You should define a custom appender with `kind: file` 282 283```yaml 284logging: 285 appenders: 286 file: 287 kind: file 288 path: /var/log/opensearch_dashboards.log 289 layout: 290 kind: pattern 291 loggers: 292 - context: plugins.myPlugin 293 appenders: [file] 294``` 295 296#### logging.json 297 298Defines the format of log output. Logs in JSON if `true`. With new logging config you can adjust 299the output format with [layouts](#layouts). 300 301#### logging.quiet 302 303Suppresses all logging output other than error messages. With new logging, config can be achieved 304with adjusting minimum required [logging level](#log-level). 305 306```yaml 307 loggers: 308 - context: plugins.myPlugin 309 appenders: [console] 310 level: error 311# or for all output 312logging.root.level: error 313``` 314 315#### logging.silent: 316 317Suppresses all logging output. 318 319```yaml 320logging.root.level: off 321``` 322 323#### logging.verbose: 324 325Logs all events 326 327```yaml 328logging.root.level: all 329``` 330 331#### logging.timezone 332 333Set to the canonical timezone id to log events using that timezone. New logging config allows 334to [specify timezone](#date) for `layout: pattern`. 335 336```yaml 337logging: 338 appenders: 339 custom-console: 340 kind: console 341 layout: 342 kind: pattern 343 highlight: true 344 pattern: '[%level] [%date{ISO8601_TZ}{America/Los_Angeles}][%logger] %message' 345``` 346 347#### logging.events 348 349Define a custom logger for a specific context. 350 351#### logging.filter 352 353TBD 354 355### Log record format changes 356 357| Parameter | Platform log record in **pattern** format | Legacy Platform log record **text** format | 358| ---------- | ----------------------------------------- | ------------------------------------------ | 359| @timestamp | ISO8601 `2012-01-31T23:33:22.011Z` | Absolute `23:33:22.011` | 360| context | `parent.child` | `['parent', 'child']` | 361| level | `DEBUG` | `['debug']` | 362| meta | stringified JSON object `{"to": "v8"}` | N/A | 363| pid | can be configured as `%pid` | N/A | 364 365| Parameter | Platform log record in **json** format | Legacy Platform log record **json** format | 366| ---------- | ------------------------------------------ | ------------------------------------------ | 367| @timestamp | ISO8601_TZ `2012-01-31T23:33:22.011-05:00` | ISO8601 `2012-01-31T23:33:22.011Z` | 368| context | `context: parent.child` | `tags: ['parent', 'child']` | 369| level | `level: DEBUG` | `tags: ['debug']` | 370| meta | separate property `"meta": {"to": "v8"}` | merged in log record `{... "to": "v8"}` | 371| pid | `pid: 12345` | `pid: 12345` | 372| type | N/A | `type: log` | 373| error | `{ message, name, stack }` | `{ message, name, stack, code, signal }` | 374