More

Logging

Actors provide a built-in way to log complex data to the console.

When dealing with lots of data, console.log often doesn't cut it. Using this.log allows you to log complex data using structured logging.


Log levels

There are 5 log levels:

LevelCallDescription
Criticalthis.log.critical(message, ...args);Severe errors that prevent core functionality
Errorthis.log.error(message, ...args);Errors that affect functionality but allow continued operation
Warningthis.log.warn(message, ...args);Potentially harmful situations that should be addressed
Infothis.log.info(message, ...args);General information about significant events & state changes
Debugthis.log.debug(message, ...args);Detailed debugging information, usually used only in development

Structured logging

The built-in logging API (using this.log) provides structured logging to let you log key-value pairs instead of raw strings. Structures logs are readable by both machines & humans to make them easier to parse & search.

Passing an object to a log will print as structured data. For example:

this.log.info('increment', { connection: rpc.connection.id, count });
// Prints: level=INFO msg=increment connection=123 count=456
TypeScript

The first parameter in each log method is the message. The rest of the arguments are used for structured logging.


this.log vs console.log logging

this.log makes it easier to manage complex logs, while console.log can become unmaintainable at scale.

Consider this example:

export default class Counter extends Actor<State> {
  increment(rpc: Rpc<this>, count: number): number {
    // Prints: level=INFO msg=increment connection=123 count=456
    this.log.info('increment', { connection: rpc.connection.id, count });

    this.state.count += count;
    return this.state.count;
  }

  // ...etc...
}

If you need to search through a lot of logs, it's easier to read the structured logs. To find increments for a single connection, you can search connection=123.

Additionally, structured logs can be parsed and queried at scale using tools like Elasticsearch, Loki, or Datadog. For example, you can parse the log level=INFO msg=increment connection=123 count=456 in to the JSON object {"level":"INFO","msg":"increment","connection":123,"count":456} and then query it as you would any other structured data.


Configuring logging

The Rivet logging API is powered by the @std/log package.

By default, logs are printed in logfmt format for a balance between machine & human readability. To configure the logging format yourself, you can call the setup function in _onStart.