Usage¶
Configure logging programmatically¶
import seqlog
seqlog.log_to_seq(
server_url="http://my-seq-server:5341/",
api_key="My API Key",
level=logging.INFO,
batch_size=10,
auto_flush_timeout=10, # seconds
override_root_logger=True,
json_encoder_class=json.encoder.JSONEncoder, # Optional; only specify this if you want to use a custom JSON encoder
support_extra_properties=True # Optional; only specify this if you want to pass additional log record properties via the "extra" argument.
)
For the best experience, use {x}
-style named format arguments (passing those format arguments as keyword arguments to the log functions info
, warning
, error
, critical
, etc).
Using unnamed “holes” (i.e. {}
) is not currently supported.
For example:
logging.info("Hello, {name}!", name="World")
If you specify ordinal arguments, the log message is interpreted as a “%s”-style format string. The ordinal format arguments are stored in the log entry properties using the 0-based ordinal index as the property name.
logging.info("Hello, %s!", "World")
Note that mixing named and ordinal arguments is not currently supported.
The formal definition of the configure function is as follows:
- seqlog.log_to_seq(server_url, api_key=None, level=30, batch_size=10, auto_flush_timeout=None, additional_handlers=None, override_root_logger=False, json_encoder_class=None, support_extra_properties=False, support_stack_info=False, ignore_seq_submission_errors=False, use_clef=False, **kwargs)[source]¶
Configure the logging system to send log entries to Seq.
Note that the root logger will not log to Seq by default.
- Parameters
server_url – The Seq server URL.
api_key – The Seq API key (optional).
level – The minimum level at which to log.
batch_size – The number of log entries to collect before publishing to Seq.
auto_flush_timeout – If specified, the time (in seconds) before the current batch is automatically flushed.
additional_handlers – Additional `LogHandler`s (if any).
override_root_logger – Override the root logger, too? Note - this might cause problems if third-party components try to be clever when using the logging.XXX functions.
json_encoder_class – The custom JSONEncoder class (if any) to use. It not specified, the default JSONEncoder will be used.
support_extra_properties (bool) – Support passing of additional properties to log via the extra argument?
support_stack_info (bool) – Support attaching of stack-trace information (if available) to log records?
ignore_seq_submission_errors (bool) – Ignore errors encountered while sending log records to Seq?
use_clef (bool) – use more modern format to send events to Seq
- Returns
The SeqLogHandler that sends events to Seq. Can be used to forcibly flush records to Seq.
- Return type
Configure logging from a file¶
Seqlog can also use a YAML-format file to describe the desired logging configuration. This file has the schema specified in Python’s logging.config module.
First, create your configuration file (e.g. /foo/bar/my_config.yml
):
# This is the Python logging schema version (currently, only the value 1 is supported here).
version: 1
# Configure logging from scratch.
disable_existing_loggers: True
# Configure the root logger to use Seq
root:
level: INFO
handlers:
- seq
- console
# You can also configure non-root loggers.
loggers:
another_logger:
propagate: False
level: INFO
handlers:
- seq
- console
handlers:
# Log to STDOUT
console:
class: seqlog.structured_logging.ConsoleStructuredLogHandler
formatter: seq
# Log to Seq
seq:
class: seqlog.structured_logging.SeqLogHandler
formatter: seq
# Seq-specific settings (add any others you need, they're just kwargs for SeqLogHandler's constructor).
server_url: 'http://localhost:5341'
api_key: 'your_api_key_if_you_have_one'
# Use a custom JSON encoder, if you need to.
json_encoder_class: json.encoder.JSONEncoder
formatters:
seq:
style: '{'
Then, call seqlog.configure_from_file()
:
seqlog.configure_from_file('/foo/bar/my_config.yml')
# Use the root logger.
root_logger = logging.getLogger()
root_logger.info('This is the root logger.')
# Use another logger
another_logger = logging.getLogger('another_logger')
another_logger.info('This is another logger.')
Configuring logging from a dictionary¶
Seqlog can also use a dictionary to describe the desired logging configuration. This dictionary has the schema specified in Python’s logging.config module.
config = {
# configuration goes here
}
seqlog.configure_from_dict(config)
# Use the root logger.
root_logger = logging.getLogger()
root_logger.info('This is the root logger.')
# Use another logger
another_logger = logging.getLogger('another_logger')
another_logger.info('This is another logger.')
Batching and auto-flush¶
By default SeqLog will wait until it has a batch of 10 messages before sending them to Seq.
You can control the batch size by passing a value for batch_size
.
If you also want it to publish the current batch of events when not enough of them have arrived within a certain period, you can pass auto_flush_timeout
(a float
representing the number of seconds before an incomplete batch is published).
Overriding the root logger¶
By default, SeqLog does not modify the root logger (and so calls to logging.info()
and friends do not support named format arguments).
To also override the root logger, pass True
for override_root_logger
.
Additional LogHandlers¶
By default, log_to_seq
only configures a single SeqLogHandler.
To configure additional LogHandlers, pass them via additional_handlers
.
Global log properties¶
SeqLog can also add static properties to each log entry that is sent to Seq. By default, the following properties are added:
MachineName
The local machine’s fully-qualified host name.ProcessId
The current process Id.
To configure global log properties, call set_global_log_properties
, passing the properties as keyword arguments:
import seqlog
seqlog.set_global_log_properties(
GlobalProperty1="foo",
GlobalProperty2="bar"
GlobalProperty3=26
)
Note that you can also clear the global log properties (so no properties are added) by calling clear_global_log_properties
, and reset the global log properties to their defaults by calling reset_global_log_properties
.
Note that is you specify a callable as part of global log properties, it will be called with no arguments right before logging:
import seqlog
def get_trace_id():
if tracer.active_span is not None:
return hex(tracer.active_span.context.trace_id)
else:
return None
seqlog.set_global_log_properties(
trace_id=get_trace_id,
)
If the callable returns None, it won’t be added.
Note that some properties get different treatment if the CLEF mode is enabled.
Note that there is a short list of these, these won’t be attached to Properties. They will get removed from there and attached according to the `CLEF<https://clef-json.org/>`_ format:
span_id
- this will get removed and be replaced with@sp
trace_id
- this will get removed and be replaced with@tr
Callback on log submission failure¶
If you wish to set a callable to be invoked each time log submission fails, use the following function:
from seqlog import set_callback_on_failure
def handle_a_failure(e): # type: (requests.RequestException) -> None
print('Failure occurred during log submission: %s' % (e, ))
set_callback_on_failure(handle_a_failure)
The callable that you provide will accept a single positional argument, which is the requests exception instance that was the reason for the fail.
Note
This callable will be called only for I/O errors, errors stemming from seqlog not being able to convert your records into JSON won’t show up here!
Passing in exceptions¶
There’s a couple of ways you can pass in exception information. The only field sent to Seq will be called Exception and it may come from a couple of places, in order:
A previously rendered exception was cached
If FeatureFlag.STACK_INFO is enabled,
stack_info
is set andexc_info
is not set, it will be taken fromstack_info
- If
exc_info
is a tuple then If it’s first element is None, FeatureFlag.STACK_INFO is enabled and
record.stack_info
is available,stack_info
will be used to construct the messageElse formatted
exc_info
will be used
- If
If only
exc_info
is given, and it’s an Exception, then the stack trace will be attached.If
exc_info
is a string, it will be attached. This is functionally the same thing as (2).
So if you provide both exc_info
and stack_info
the code will behave in a way that’s hard to put into words.