Skip to content

Logging

This tutorial shows how to enable and use structured logging in pysenxor. The library uses structlog so you get consistent, key-value log lines that are easy to filter and parse (e.g. for debugging connection, register access, or streaming).

1. Default behavior

When you import senxor, a standard logger is configured automatically. The default log level is WARNING, so under normal use you will not see info-level messages. This keeps the library from affecting your application’s logging when you use pysenxor as a dependency.

To see more detail (e.g. device open/close, register reads/writes, stream start/stop), enable console or file logging as below.

2. Enable console logging

Call setup_console_logger at the start of your script so that senxor logs are printed to the console with a readable, colored format. Pass the desired level (e.g. "INFO" or "DEBUG").

from senxor.log import setup_console_logger
from senxor import connect, list_senxor

setup_console_logger("INFO")

devices = list_senxor("serial")
if not devices:
    raise ValueError("No devices found")

dev = connect(devices[0])
print(dev.get_fw_version())
dev.close()

Output (example):

2026-03-02T14:06:22+0800 [info     ] init_senxor_instance           name=COM4 interface='SerialInterface - COM4'
2026-03-02T14:06:22+0800 [info     ] opening_senxor                 name=COM4
2026-03-02T14:06:22+0800 [info     ] read_reg_success               name=COM4 op=read addr=177 value=32 updated_fields={'GET_SINGLE_FRAME': 0, 'CONTINUOUS_STREAM': 0, 'READOUT_MODE': 0, 'NO_HEADER': 1, 'ADC_ENABLE': 0}
2026-03-02T14:06:22+0800 [info     ] write_reg_success              name=COM4 op=write addr=177 value=32 updated_fields={}
2026-03-02T14:06:22+0800 [info     ] set_field_success              name=CONTINUOUS_STREAM value=0
2026-03-02T14:06:22+0800 [info     ] stop_stream_success            name=COM4
2026-03-02T14:06:22+0800 [info     ] read_reg_success               name=COM4 op=read addr=178 value=70 updated_fields={'FW_VERSION_MAJOR': 4, 'FW_VERSION_MINOR': 6}
...

setup_console_logger(log_level="INFO", logger_name="senxor", add_logger_name=False) lets you set the level, logger name, and whether to show the logger name in each line.

3. Log levels

Use standard levels: "DEBUG", "INFO", "WARNING", "ERROR". Pass them as strings or use logging constants.

from senxor.log import setup_console_logger

setup_console_logger("DEBUG")

"DEBUG" gives the most detail; "INFO" is usually enough for connection and register activity.

4. Log to a file

Use setup_file_logger to write senxor logs to a file. You can use plain text (default) or JSON.

from senxor.log import setup_file_logger
from senxor import connect, list_senxor

setup_file_logger("senxor.log", log_level="INFO")

devices = list_senxor("serial")
if not devices:
    raise ValueError("No devices found")

dev = connect(devices[0])
dev.close()

Append to an existing file:

setup_file_logger("senxor.log", file_mode="a", log_level="INFO")

JSON format (one line per event) for later analysis or ingestion:

setup_file_logger("senxor.log", log_level="INFO", json_format=True)

For log rotation or external tools that replace the file, use watch_file=True so the handler reopens the file when it changes:

setup_file_logger("senxor.log", log_level="INFO", watch_file=True)

5. Use get_logger in your own code

If your application also wants structured logs in the same style, use get_logger. Any keyword arguments you pass are bound to every log event (e.g. device identifier).

from senxor.log import get_logger

logger = get_logger()
logger.info("custom_event", temperature=25.3)

Output (with console logger enabled): the event and key-value pairs (e.g. temperature=25.3) appear in the same format as the library logs.

6. Multiple loggers and custom pipelines (advanced)

After you understand the basic get_logger usage, you can build more advanced pipelines by using different logger names. Logger names act as separate logging pipelines. The default name used inside the library is "senxor", and both setup_console_logger and setup_file_logger attach handlers to a specific logger_name. By choosing different names, you can keep library logs and application logs completely separate.

For example, send Senxor logs (WARNING and above) to the console, and application logs (INFO and above) to a file:

from senxor.log import setup_console_logger, setup_file_logger, get_logger

# Senxor logs: WARNING+ to console
setup_console_logger("WARNING", logger_name="senxor")


# Application logs: INFO+ to file
app_log = get_logger("my_app", app_name="demo")
setup_file_logger("my_app.log", log_level="INFO", logger_name="my_app")

app_log.info("app_started")

In this example, senxor_log uses the "senxor" pipeline (console), and app_log uses the "my_app" pipeline (file). The first argument to get_logger is the logger name; any keyword arguments (such as app_name="demo") are bound as extra context on each event.