easyfabric.fabric.logging_utils
ExcludeLoggersFilter Objects
class ExcludeLoggersFilter(logging.Filter)
Drops records from EXCLUDED_LOGGERS so progress/metrics noise stays out of the OneLake log file (and therefore the logging table).
is_top_level_notebook
def is_top_level_notebook() -> bool
Identifies if the current execution is the top-most notebook.
A notebook is top-level when it was not invoked via notebookutils.notebook.run from another notebook. Fabric sets isReferenceRun=True on every child invocation and False (or absent) on the entry-point notebook.
save_log_file_to_table
def save_log_file_to_table(end_log: bool = False) -> None
Reads a log file from OneLake, parses structured logs (including multiline), and bulk inserts into Meta.dbo.logging using Spark DataFrame.
If it's a top-level notebook or end_log is True, logs an END entry with duration, persists log entries to the table and only then clears the logging handlers and resets state. Otherwise returns without emitting anything.
A failed persist stays visible: the failure is logged while the handlers are still attached and printed to the cell output, which survives both the handler cleanup and a log table that could not be written.
flush_log_handlers
def flush_log_handlers() -> None
Write out every entry the log handlers are still holding. Never raises.
save_historical_log_file_to_table
def save_historical_log_file_to_table(abfs_path: str) -> None
Parses a specific log file by ABFS path and inserts missing logs into Meta.dbo.logging.
FabricLoggerAdapter Objects
class FabricLoggerAdapter(logging.LoggerAdapter)
Adapter that automatically includes log_type and log_category in all log records.
OneLakeFileHandler Objects
class OneLakeFileHandler(logging.Handler)
Appends log entries to the OneLake file a whole batch shares.
notebookutils.fs.append is an offset write, so concurrent writers collide
on InvalidFlushPosition. A write runs against a deadline instead of a try
count, and an entry that does not land is held and written with the next one.
No single write has to be won, so the deadline only has to outlast ordinary
contention; waiting longer would hold the handler lock for nothing. Waiting
is bounded per write and per run.
flush
def flush()
Write what is still held. Takes the lock emit gets from handle.
SafeFormatter Objects
class SafeFormatter(logging.Formatter)
Formatter that ensures custom fields exist to prevent KeyErrors from third-party libraries.
formatTime
def formatTime(record, datefmt=None)
Include milliseconds in the timestamp for better sorting.
to_snake_case
def to_snake_case(string: str) -> str
Convert a string from camel case to snake case.
set_verbose_mode
def set_verbose_mode(enabled=True)
Enable or disable verbose logging mode globally.
SegmentHandle Objects
class SegmentHandle()
Context manager returned by log_segment(). Accumulates a structured
payload during the segment and emits it as |CTX:{...}| JSON on the
END line. Four outcome states: Success (default), Skipped, Unchanged,
Failed (exception escaped).
log_segment
def log_segment(type: str, name: str) -> SegmentHandle
Context manager to log the start and end of a logic segment. Usage: with log_segment("Data Load", "Bronze Loading") as seg: seg.record(files=nr_of_files) if skipped_by_config: seg.skip(reason="loadskip_configured") return if nothing_to_do: seg.unchanged(reason="files_unchanged") return ... logic ...
current_segment
def current_segment() -> Optional[SegmentHandle]
Return the innermost active segment, or None if outside a segment.
segment_record
def segment_record(**kwargs) -> None
Record kwargs onto the current segment's payload. No-op if no segment is active.
segment_accumulate
def segment_accumulate(**kwargs) -> None
Add kwargs to the current segment's payload, summing with any value already recorded under the same key. Use it for measures that a batch produces in parts (rows written per source file) so the END record carries the batch total. No-op if no segment is active.
segment_skip
def segment_skip(reason: str) -> None
Mark the current segment as Skipped. No-op if no segment is active.
segment_unchanged
def segment_unchanged(reason: str) -> None
Mark the current segment as Unchanged. No-op if no segment is active.
init_logging
def init_logging(log_source: str = "Sys",
log_object: str = None,
base_batch_id: str = None) -> str
Call once at the very top of the entry-point notebook / wheel. Returns the absolute OneLake path of the log file.
base_batch_id keeps a whole logical run under one batch_id when a
parent offloads children as separate Fabric jobs (each gets its own
activityId). Pass the parent's id explicitly through every notebook
boundary; absent it, the notebook's own activityId is used. The log file
name always uses the own activityId so concurrent jobs write distinct
files.
parent_run_id resolves to: the native Fabric parentRunId when
present; else, for a reference run (notebook.run child), the own
activityId — which equals the calling notebook's run id; else
base_batch_id so an offloaded entry notebook links to the root run.
get_log_file_path
def get_log_file_path() -> Optional[str]
Returns the path of the current log file. Checks singleton state, global config, and active handlers to ensure reliability even in nested notebooks or after module reloads.
extract_real_error
def extract_real_error(log_text: str) -> str
Extracts the most relevant error message from a Spark stack trace.
A NotebookExecutionException (child notebook failure via notebookutils.notebook.run)
carries the child's real error on the lines after the exception name, so that block is
returned as a whole, up to the JVM stack frames.
Otherwise the most specific named Spark error wins; when a Caused by: chain is present
its last link is appended to the primary line instead of replacing it, so the informative
Python-level exception line survives next to the JVM root cause.