Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/environment-configs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Environment configurations

`daqpytools` has the power for you to configure your current instance of the loggings! This allows each user to change the timezone and the color themes to suit them as the logs come out.

The way this is configured is by setting environment variables. By default, these are _unset_ in the terminal, which daqpytools will read and resolve to a default value. These default values can be found in `logging/log_format.ini`.

Comment thread
PawelPlesniak marked this conversation as resolved.
If a non-default time zone/theme is preferred, it is recommended to set the env vars `DUNEDAQ_TIMEZONE` and `DUNEDAQ_LOGGING_THEME` in your `~/.bashrc`.

## Timezones

To change the timezone, simply do

`export DUNEDAQ_TIMEZONE="[timezone]"`

eg. `export DUNEDAQ_TIMEZONE="UTC"`

Valid values are those that are listed in `pytz.all_timezones`.

An example with `Europe/London`.

![timezones](img/timezone.png)


## Logging themes

The themes are defined in daqpytools, in `logging/themes`, where you can see all the different themes available. To change between them, simply do

`export DUNEDAQ_LOGGING_THEME="[themename]"`

eg. `export DUNEDAQ_LOGGING_THEME="dark"`

There are checks in place to ensure that the theme choice is valid before logs are printed.

An example with `black`.
![themes](img/theme.png)
Binary file added docs/img/theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/timezone.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ This documentation is split into two sections depending on your role:
| [Best practices](./how-to/best-practices.md) | Recommended patterns for structuring logging in your application |
| [Troubleshooting](./reference/troubleshooting.md) | Common symptoms, causes, and fixes |
| [API reference](../APIref/) | Auto-generated kwargs, types, and defaults for all public APIs (redirects to MKDocs website) |
| [Environment configs](./environment-configs.md) | Extra information on how to configure your local copy of the logging. |

2 changes: 1 addition & 1 deletion docs_dev/how-to/update-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ If you are new to this repo, read this first before editing docs.

The docs are assembled from multiple sources at build time:

- `docs/` contains user-facing content
- `docs/` contains user-facing content. **Note that this is also used in the dunedaq readthedocs.**
Comment thread
emmuhamm marked this conversation as resolved.
- `docs_dev/` contains developer-facing content
- `docs_dev/utils/generate_logging_autodocs.py` generates API reference pages from Python registries
- `docs_dev/utils/mirror_docs.py` mirrors everything into a virtual docs tree
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ nav:
- How docs work and how to update them: dev/how-to/update-documentation.md
- Common patterns: dev/reference/patterns.md
- API reference: APIref
- Environment configurations: user/environment-configs.md

theme:
name: material
palette:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ version = "1.0.0"
where = ["src"]

[tool.setuptools.package-data]
"daqpytools.logging" = ["log_format.ini"]
"daqpytools.logging" = ["log_format.ini", "themes/*.ini"]
"daqpytools.uml" = ["uml_format.ini"]

[project.optional-dependencies]
Expand Down
21 changes: 20 additions & 1 deletion src/daqpytools/logging/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,28 @@
LOG_FORMAT = config_loader.safe_load_config("logging", "record_format")
DATE_TIME_FORMAT = config_loader.safe_load_config("logging", "date_time")
DATE_TIME_BASE_FORMAT = config_loader.safe_load_config("logging", "date_time_base")


def load_and_return(env: str) -> str:
"""Loads the env into the config, and then returns it safely."""
config_loader.load_env(env)
return config_loader.safe_load_config(
"environment", env
)


theme_path = Path(DAQPYTOOLS_LOGGING_ROOT /
f"themes/{load_and_return('DUNEDAQ_LOGGING_THEME')}.ini")
if not theme_path.is_file():
err_msg = (f"{load_and_return('DUNEDAQ_LOGGING_THEME')} is not"
"a valid theme file! Change your DUNEDAQ_LOGGING_THEME variable")
raise ValueError(err_msg)

config_loader.read_conf(theme_path)
CONSOLE_THEME = Theme(config_loader.safe_load_config("theme"))

timezone_name = config_loader.safe_load_config("logging", "timezone")

timezone_name = load_and_return("DUNEDAQ_TIMEZONE")
try:
TIME_ZONE = timezone(timezone_name)
except UnknownTimeZoneError as e:
Expand Down
31 changes: 7 additions & 24 deletions src/daqpytools/logging/log_format.ini
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,13 @@ logger_name = 50
record_format=%%(asctime)s %%(levelname)s %%(filename)s %%(name)s %%(message)s
date_time_base=%%Y/%%m/%%d %%H:%%M:%%S %%Z
date_time=[%(date_time_base)s]
timezone=UTC

[theme]
# Define the color theme for logging output
# Colors can be set to 'dim', 'bold', or 'bright' variants of the colors
# Available colors: black, red, green, yellow, blue, magenta, cyan
# Background colors can be set with 'on_' prefix

# === Context elements ===
# Available colors: black, red, green, yellow, blue, magenta, cyan, white
# You can also use: bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
# Styles: dim, bold, italic, underline, reverse, blink, conceal, strike
# Combine styles and colors, e.g., "bold magenta", "dim cyan", "bold white on red"
logging.time = dim blue
logging.location = dim white
logging.logger_name = dim white

# === Log level colors ===
logging.level.debug = dim cyan
logging.level.info = bold green
logging.level.warning = bold yellow
logging.level.error = bold red
logging.level.critical = bold white on red

[cli]
# Command-line interface options
help_option_names = -h,--help
help_option_names = -h,--help

[environment]
# These can be overridden from the environment variables
# the current ones here show what the default is
DUNEDAQ_LOGGING_THEME = default
DUNEDAQ_TIMEZONE = UTC
27 changes: 27 additions & 0 deletions src/daqpytools/logging/themes/black.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[theme]
# Define the color theme for logging output
# Colors can be set to 'dim', 'bold', or 'bright' variants of the colors
# Available colors: black, red, green, yellow, blue, magenta, cyan
# Background colors can be set with 'on_' prefix

# === Context elements ===
# Available colors: black, red, green, yellow, blue, magenta, cyan, white
# You can also use: bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
# Styles: dim, bold, italic, underline, reverse, blink, conceal, strike
# Combine styles and colors, e.g., "bold magenta", "dim cyan", "bold white on red"
# Rich color reference: https://rich.readthedocs.io/en/stable/appendix/colors.html
# Rich style reference: https://rich.readthedocs.io/en/latest/style.html

# Theme specific details
# This one makes everything black, which is a nice colorless default for people to use

logging.time = black
logging.location = black
logging.logger_name = black

# === Log level colors ===
logging.level.debug = black
logging.level.info = black
logging.level.warning = black
logging.level.error = black
logging.level.critical = black
27 changes: 27 additions & 0 deletions src/daqpytools/logging/themes/dark.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[theme]
# Define the color theme for logging output
# Colors can be set to 'dim', 'bold', or 'bright' variants of the colors
# Available colors: black, red, green, yellow, blue, magenta, cyan
# Background colors can be set with 'on_' prefix

# === Context elements ===
# Available colors: black, red, green, yellow, blue, magenta, cyan, white
# You can also use: bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
# Styles: dim, bold, italic, underline, reverse, blink, conceal, strike
# Combine styles and colors, e.g., "bold magenta", "dim cyan", "bold white on red"
# Rich color reference: https://rich.readthedocs.io/en/stable/appendix/colors.html
# Rich style reference: https://rich.readthedocs.io/en/latest/style.html

# Theme specific details
# Safe to use on all dark (including black) themes. The colors should still be legible.

logging.time = blue
logging.location = grey74
logging.logger_name = grey74

# === Log level colors ===
logging.level.debug = cyan
logging.level.info = bold green
logging.level.warning = bold yellow
logging.level.error = bold red
logging.level.critical = bold white on red
27 changes: 27 additions & 0 deletions src/daqpytools/logging/themes/default.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[theme]
# Define the color theme for logging output
# Colors can be set to 'dim', 'bold', or 'bright' variants of the colors
# Available colors: black, red, green, yellow, blue, magenta, cyan
# Background colors can be set with 'on_' prefix

# === Context elements ===
# Available colors: black, red, green, yellow, blue, magenta, cyan, white
# You can also use: bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
# Styles: dim, bold, italic, underline, reverse, blink, conceal, strike
# Combine styles and colors, e.g., "bold magenta", "dim cyan", "bold white on red"
# Rich color reference: https://rich.readthedocs.io/en/stable/appendix/colors.html
# Rich style reference: https://rich.readthedocs.io/en/latest/style.html

# Theme specific details
# Safe to use on all light (including white) themes. The colors should still be legible.

logging.time = dim blue
logging.location = dim white
logging.logger_name = dim white

# === Log level colors ===
logging.level.debug = dim cyan
logging.level.info = bold green
logging.level.warning = bold yellow
logging.level.error = bold red
logging.level.critical = bold white on red
27 changes: 27 additions & 0 deletions src/daqpytools/logging/themes/light.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[theme]
# Define the color theme for logging output
# Colors can be set to 'dim', 'bold', or 'bright' variants of the colors
# Available colors: black, red, green, yellow, blue, magenta, cyan
# Background colors can be set with 'on_' prefix

# === Context elements ===
# Available colors: black, red, green, yellow, blue, magenta, cyan, white
# You can also use: bright_black, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white
# Styles: dim, bold, italic, underline, reverse, blink, conceal, strike
# Combine styles and colors, e.g., "bold magenta", "dim cyan", "bold white on red"
# Rich color reference: https://rich.readthedocs.io/en/stable/appendix/colors.html
# Rich style reference: https://rich.readthedocs.io/en/latest/style.html

# Theme specific details
# This one makes everything black, which is a nice colorless default for people to use

logging.time = blue
logging.location = bright_black
logging.logger_name = bright_black

# === Log level colors ===
logging.level.debug = cyan
logging.level.info = bold green
logging.level.warning = bold yellow
logging.level.error = bold red
logging.level.critical = bold white on red
38 changes: 35 additions & 3 deletions src/daqpytools/utils/config_loader.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import configparser
import os
from pathlib import Path
from typing import overload

Expand Down Expand Up @@ -34,8 +34,12 @@ def __init__(self, config_file: Path | str) -> None:
"""
self.config_file = config_file
self.config: configparser.ConfigParser = configparser.ConfigParser()

if not self.config.read(self.config_file):
self.read_conf(self.config_file)


def read_conf(self, conf: str) -> None:
"""Reads and loads a given config file."""
if not self.config.read(conf):
err_msg = (
f"Configuration file '{self.config_file}' "
"not found or could not be read."
Expand All @@ -60,6 +64,34 @@ def safe_load_config(
...


# define a thing that lets you parse environment variables
def load_env(self, env_key: str) -> str | None:
"""Read an environment variable and insert it into the
``environment`` section of the internal ``ConfigParser``.

If the section does not exist it will be created. The method stores
the variable only when it is set and non-empty; if the variable is
not set (or is an empty string), the config is left unchanged and
the method returns ``None``. This differs from earlier behaviour that
used to write an empty string for unset variables.

Returns the environment value or ``None`` if the variable is not set
or is empty.
"""
env_value = os.environ.get(env_key)
section = "environment"
if not self.config.has_section(section):
self.config.add_section(section)

# Only store the value when the environment variable is set and
# non-empty. If the variable is unset or empty, leave the config
# unchanged and return None.
if env_value:
self.config.set(section, env_key, env_value)

return env_value


def safe_load_config(
self,
section: str,
Expand Down
Loading