gale.log package

gale.log: logging for gale games, configured to print to the terminal and write to a plain-text file by default, and extensible to send records anywhere else (Graylog, Sentry, a Discord channel, and friends) by attaching another logging.Handler — each handler is itself the “where do records go” strategy, so a game only ever composes handlers, never writes a new one unless it needs a destination gale/the standard library doesn’t already ship.

See docs/examples/log.rst for a walkthrough.

Author: Alejandro Mujica (aledrums@gmail.com)

class gale.log.DiscordWebhookHandler(webhook_url, username=None, timeout=2.0)[source]

Bases: Handler

Posts every log record to a Discord channel through an incoming webhook — a common, zero-infrastructure way for a small/solo team to get pinged about errors and warnings without standing up a full log aggregation stack. Uses only the standard library.

Since pinging a channel for every single INFO line would be noisy, this is typically attached with a raised level, e.g. only WARNING/ERROR and above:

Usage example:

from gale.log import add_handler from gale.log.level import LogLevel from gale.log.discord_webhook_handler import DiscordWebhookHandler

handler = DiscordWebhookHandler(

https://discord.com/api/webhooks/<id>/<token>”, username=”space_trip”

) handler.setLevel(LogLevel.WARNING) add_handler(handler)

Parameters:
  • webhook_url (str)

  • username (str | None)

  • timeout (float)

emit(record)[source]

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

Parameters:

record (LogRecord)

Return type:

None

class gale.log.GraylogHandler(host, port, source=None)[source]

Bases: Handler

Sends every log record to a Graylog server as a GELF (Graylog Extended Log Format) datagram over UDP — one strategy among possibly several; register it with gale.log.add_handler to start sending records there in addition to (or, with gale.log.configure(console=False, log_file=None), instead of) the console/file defaults. Any other logging.Handler works exactly the same way, GraylogHandler is just the one gale ships since the standard library doesn’t have one.

Usage example:

from gale.log import add_handler from gale.log.graylog_handler import GraylogHandler

add_handler(GraylogHandler(“graylog.example.com”, 12201))

Parameters:
  • host (str)

  • port (int)

  • source (str | None)

emit(record)[source]

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

Parameters:

record (LogRecord)

Return type:

None

close()[source]

Tidy up any resources used by the handler.

This version removes the handler from an internal map of handlers, _handlers, which is used for handler lookup by name. Subclasses should ensure that this gets called from overridden close() methods.

Return type:

None

class gale.log.LogLevel[source]

Bases: object

The severities a log record can have, in increasing order of severity. These are exactly Python’s own logging levels — kept under gale’s own name so a game never has to import the standard library’s logging module just to pick a level.

DEBUG: int = 10
INFO: int = 20
WARNING: int = 30
ERROR: int = 40
CRITICAL: int = 50
class gale.log.SentryHandler(dsn, timeout=2.0)[source]

Bases: Handler

Sends every log record to Sentry (sentry.io or a self-hosted instance) as an event through its HTTP Store API, using only the standard library — no sentry-sdk dependency. It’s a lightweight “at least get pinged about errors” integration; for full Sentry features (breadcrumbs, releases, performance tracing, offline queuing/retry…) use sentry-sdk directly instead.

Usage example:

from gale.log import add_handler from gale.log.sentry_handler import SentryHandler

add_handler(SentryHandler(”https://<public_key>@<host>/<project_id>”))

Parameters:
  • dsn (str)

  • timeout (float)

emit(record)[source]

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

Parameters:

record (LogRecord)

Return type:

None

gale.log.add_handler(handler)[source]

Attach an additional handler — a strategy for where log records should also go, such as a GraylogHandler — to gale’s logger, on top of whatever configure() set up.

Parameters:

handler (Handler) – The handler to add.

Return type:

None

gale.log.configure(level=20, log_file='gale.log', console=True)[source]

Set up gale’s default logging: a console handler and/or a plain-text file handler. Call this once, as early as convenient (get_logger auto-configures with these same defaults on first use if you never call this explicitly, so calling it is only needed to override the defaults).

Extra “strategies” — where else records should go, such as a Graylog server — are added on top of whatever this sets up, with add_handler; calling configure again replaces the console/file handlers but leaves any handler added through add_handler alone.

Parameters:
  • level (int) – The minimum severity to emit, one of the LogLevel constants. The default value is LogLevel.INFO.

  • log_file (str | None) – Path to the plain-text log file to write to. The default value is “gale.log”. Pass None to disable file logging.

  • console (bool) – Whether to also print log records to the terminal. The default value is True.

Return type:

None

gale.log.get_logger(name=None)[source]
Parameters:

name (str | None) – A dotted name for the logger, nested under gale’s own (e.g. “space_trip.player” becomes “gale.space_trip.player”). The default value is None, returning gale’s own top-level logger.

Returns:

A standard library Logger, so it composes with anything else that already understands logging.Logger. Auto-configures with configure()’s defaults on first use if configure() was never called explicitly.

Return type:

Logger

gale.log.remove_handler(handler)[source]
Parameters:

handler (Handler) – The handler to remove, previously passed to add_handler.

Return type:

None

Submodules