"""
Java java.util.logging standard library APIs implemented in Python.
java.util.logging package - Logger, Level, Handler, Formatter, etc.
"""
from __future__ import annotations
from .._core import Stub
from .lang import RuntimeException, Exception as _JavaException
from .security import BasicPermission
import typing as _typing
import sys as _sys
import datetime as _datetime
import io as _io
import threading as _threading
import traceback as _traceback
import os as _os
__all__ = [
"Logger", "Level",
"Handler", "ConsoleHandler", "FileHandler", "StreamHandler",
"SocketHandler", "MemoryHandler",
"Formatter", "SimpleFormatter", "XMLFormatter",
"LogRecord", "LogManager", "Filter", "ErrorManager",
"LoggingMXBean", "LoggingPermission",
"OFF", "SEVERE", "WARNING", "INFO", "CONFIG", "FINE", "FINER", "FINEST", "ALL",
]
import sys as _sys
import threading as _threading
# ============================================================
# Level Constants
# ============================================================
class _Integer:
"""Wrapper to emulate Integer.MIN_VALUE / MAX_VALUE"""
MIN_VALUE = -2147483648
MAX_VALUE = 2147483647
OFF = _Integer.MAX_VALUE
SEVERE = 1000
WARNING = 900
INFO = 800
CONFIG = 700
FINE = 500
FINER = 400
FINEST = 300
ALL = _Integer.MIN_VALUE
# ============================================================
# Level
# ============================================================
class Level(Stub):
"""java.util.logging.Level"""
def __init__(self, name, value, resource_bundle_name=None):
super().__init__()
self._name = name
self._value = value
self._resource_bundle_name = resource_bundle_name
def getName(self):
return self._name
def intValue(self):
return self._value
def getResourceBundleName(self):
return self._resource_bundle_name
def toString(self):
return self._name
def hashCode(self):
return self._value
def equals(self, other):
if not isinstance(other, Level):
return False
return self._value == other._value
def parse(self, name):
name_upper = name.upper()
level_map = {
"OFF": Level.OFF,
"SEVERE": Level.SEVERE,
"WARNING": Level.WARNING,
"INFO": Level.INFO,
"CONFIG": Level.CONFIG,
"FINE": Level.FINE,
"FINER": Level.FINER,
"FINEST": Level.FINEST,
"ALL": Level.ALL,
}
if name_upper in level_map:
return level_map[name_upper]
try:
return Level(name, int(name))
except ValueError:
raise IllegalArgumentException(f"Bad level name: {name}")
def __lt__(self, other):
if isinstance(other, Level):
return self._value < other._value
return NotImplemented
def __le__(self, other):
if isinstance(other, Level):
return self._value <= other._value
return NotImplemented
def __gt__(self, other):
if isinstance(other, Level):
return self._value > other._value
return NotImplemented
def __ge__(self, other):
if isinstance(other, Level):
return self._value >= other._value
return NotImplemented
# Static level instances
OFF = None
SEVERE = None
WARNING = None
INFO = None
CONFIG = None
FINE = None
FINER = None
FINEST = None
ALL = None
# ============================================================
# Initialize static Level instances
# ============================================================
Level.OFF = Level("OFF", _Integer.MAX_VALUE)
Level.SEVERE = Level("SEVERE", 1000)
Level.WARNING = Level("WARNING", 900)
Level.INFO = Level("INFO", 800)
Level.CONFIG = Level("CONFIG", 700)
Level.FINE = Level("FINE", 500)
Level.FINER = Level("FINER", 400)
Level.FINEST = Level("FINEST", 300)
Level.ALL = Level("ALL", _Integer.MIN_VALUE)
# ============================================================
# LogRecord
# ============================================================
class LogRecord(Stub):
"""java.util.logging.LogRecord"""
def __init__(self, level, msg):
super().__init__()
self._level = level if isinstance(level, Level) else Level.INFO
self._logger_name = ""
self._message = msg
self._millis = _datetime.datetime.now().timestamp() * 1000
self._thread_id = _threading.get_ident()
self._source_class_name = None
self._source_method_name = None
self._thrown = None
self._parameters = None
self._resource_bundle = None
self._resource_bundle_name = None
self._sequence_number = id(self)
self._long_thread_id = _threading.get_ident()
def getLevel(self):
return self._level
def setLevel(self, level):
self._level = level
def getLoggerName(self):
return self._logger_name
def setLoggerName(self, name):
self._logger_name = name
def getMessage(self):
return self._message
def setMessage(self, msg):
self._message = msg
def getMillis(self):
return self._millis
def setMillis(self, millis):
self._millis = millis
def getThreadID(self):
return self._thread_id
def setThreadID(self, thread_id):
self._thread_id = thread_id
def getSourceClassName(self):
return self._source_class_name
def setSourceClassName(self, name):
self._source_class_name = name
def getSourceMethodName(self):
return self._source_method_name
def setSourceMethodName(self, name):
self._source_method_name = name
def getThrown(self):
return self._thrown
def setThrown(self, thrown):
self._thrown = thrown
def getParameters(self):
return self._parameters
def setParameters(self, params):
self._parameters = params
def getResourceBundle(self):
return self._resource_bundle
def setResourceBundle(self, bundle):
self._resource_bundle = bundle
def getResourceBundleName(self):
return self._resource_bundle_name
def setResourceBundleName(self, name):
self._resource_bundle_name = name
def getSequenceNumber(self):
return self._sequence_number
def setSequenceNumber(self, seq):
self._sequence_number = seq
def getLongThreadID(self):
return self._long_thread_id
def setLongThreadID(self, thread_id):
self._long_thread_id = thread_id
# ============================================================
# Filter
# ============================================================
class Filter(Stub):
"""java.util.logging.Filter"""
def isLoggable(self, record):
return True
# ============================================================
# Formatter
# ============================================================
class Formatter(Stub):
"""java.util.logging.Formatter"""
def format(self, record):
raise NotImplementedError
def getHead(self, handler):
return ""
def getTail(self, handler):
return ""
def formatMessage(self, record):
msg = record.getMessage()
params = record.getParameters()
if params:
try:
return msg % params
except Exception:
pass
return msg
class SimpleFormatter(Formatter):
"""java.util.logging.SimpleFormatter"""
def format(self, record):
import datetime as dt
ts = dt.datetime.fromtimestamp(record.getMillis() / 1000.0)
ts_str = ts.strftime("%Y-%m-%d %H:%M:%S")
msg = self.formatMessage(record)
thrown = record.getThrown()
result = f"{ts_str} {record.getLevel().getName()} {record.getLoggerName()}: {msg}"
if thrown is not None:
result += "\n" + "".join(_traceback.format_exception(
type(thrown), thrown, getattr(thrown, '__traceback__', None)
))
return result
class XMLFormatter(Formatter):
"""java.util.logging.XMLFormatter"""
def __init__(self):
super().__init__()
from xml.sax.saxutils import escape
def format(self, record):
ts = _datetime.datetime.fromtimestamp(record.getMillis() / 1000.0)
ts_str = ts.strftime("%Y-%m-%dT%H:%M:%S")
from xml.sax.saxutils import escape
msg = escape(self.formatMessage(record))
logger_name = escape(record.getLoggerName() or "")
level_name = record.getLevel().getName()
parts = [
"",
f" {ts_str}",
f" {int(record.getMillis())}",
f" {record.getSequenceNumber()}",
f" {logger_name}",
f" {level_name}",
f" {escape(record.getSourceClassName() or '')}",
f" {escape(record.getSourceMethodName() or '')}",
f" {record.getThreadID()}",
f" {msg}",
]
thrown = record.getThrown()
if thrown is not None:
import traceback
tb_str = "".join(traceback.format_exception(
type(thrown), thrown, getattr(thrown, '__traceback__', None)
))
parts.append(f" {escape(tb_str)}")
parts.append("")
return "\n".join(parts)
def getHead(self, handler):
return '\n\n\n'
def getTail(self, handler):
return "\n"
# ============================================================
# ErrorManager
# ============================================================
class ErrorManager(Stub):
"""java.util.logging.ErrorManager"""
def __init__(self):
super().__init__()
def error(self, message, exception, error_code):
_sys.stderr.write(f"ErrorManager: {message}\n")
if exception:
_traceback.print_exception(type(exception), exception,
getattr(exception, '__traceback__', None))
GENERIC_FAILURE = 0
WRITE_FAILURE = 1
FLUSH_FAILURE = 2
CLOSE_FAILURE = 3
OPEN_FAILURE = 4
FORMAT_FAILURE = 5
# ============================================================
# Handler
# ============================================================
class Handler(Stub):
"""java.util.logging.Handler"""
def __init__(self):
super().__init__()
self._level = Level.ALL
self._filter = None
self._formatter = None
self._encoding = None
self._error_manager = ErrorManager()
self._closed = False
def publish(self, record):
raise NotImplementedError
def flush(self):
pass
def close(self):
self._closed = True
def isLoggable(self, record):
if self._closed:
return False
if record.getLevel().intValue() < self._level.intValue():
return False
if self._filter is not None:
return self._filter.isLoggable(record)
return True
def setLevel(self, level):
self._level = level
def getLevel(self):
return self._level
def setFilter(self, filter_):
self._filter = filter_
def getFilter(self):
return self._filter
def setFormatter(self, formatter):
self._formatter = formatter
def getFormatter(self):
return self._formatter
def setEncoding(self, encoding):
self._encoding = encoding
def getEncoding(self):
return self._encoding
def setErrorManager(self, em):
self._error_manager = em
def getErrorManager(self):
return self._error_manager
def reportError(self, msg, ex, code):
if self._error_manager:
self._error_manager.error(msg, ex, code)
class StreamHandler(Handler):
"""java.util.logging.StreamHandler"""
def __init__(self, out=None, formatter=None):
super().__init__()
if formatter is None:
formatter = SimpleFormatter()
self.setFormatter(formatter)
self._output = out or _sys.stderr
self._writer = None
if self._output is not None:
if isinstance(self._output, _io.TextIOBase):
self._writer = self._output
elif isinstance(self._output, _io.BufferedWriter):
self._writer = _io.TextIOWrapper(self._output)
else:
self._writer = _io.TextIOWrapper(_io.BufferedWriter(self._output))
def publish(self, record):
if not self.isLoggable(record):
return
try:
msg = self.getFormatter().format(record)
if self._writer is not None:
self._writer.write(msg + "\n")
else:
print(msg, file=_sys.stderr)
self.flush()
except Exception as e:
self.reportError("Error publishing record", e, ErrorManager.WRITE_FAILURE)
def flush(self):
if self._writer is not None:
try:
self._writer.flush()
except Exception:
pass
def close(self):
self.flush()
if self._writer is not None:
try:
self._writer.close()
except Exception:
pass
super().close()
def setOutputStream(self, out):
self._output = out
if isinstance(out, _io.TextIOBase):
self._writer = out
elif isinstance(out, _io.BufferedWriter):
self._writer = _io.TextIOWrapper(out)
else:
self._writer = _io.TextIOWrapper(_io.BufferedWriter(out))
class ConsoleHandler(StreamHandler):
"""java.util.logging.ConsoleHandler"""
def __init__(self):
super().__init__(_sys.stderr, SimpleFormatter())
self.setLevel(Level.INFO)
class FileHandler(Handler):
"""java.util.logging.FileHandler"""
def __init__(self, pattern=None, append=None, limit=0, count=1):
super().__init__()
self._pattern = pattern or "logging.log"
self._limit = limit
self._count = count
self._append = append or False
self._files = []
if "%u" in self._pattern or "%g" in self._pattern:
self._current_filename = self._pattern.replace("%u", "0").replace("%g", "0")
else:
self._current_filename = self._pattern
try:
mode = "a" if self._append else "w"
self._file = open(self._current_filename, mode, encoding="utf-8")
self._writer = self._file
except Exception as e:
self._file = None
self._writer = None
self.reportError("Cannot open file", e, ErrorManager.OPEN_FAILURE)
self._formatter = SimpleFormatter()
def publish(self, record):
if not self.isLoggable(record):
return
if self._writer is None:
return
try:
msg = self.getFormatter().format(record)
self._writer.write(msg + "\n")
self.flush()
except Exception as e:
self.reportError("Error publishing record", e, ErrorManager.WRITE_FAILURE)
def flush(self):
if self._writer is not None:
try:
self._writer.flush()
except Exception:
pass
def close(self):
self.flush()
if self._writer is not None:
try:
self._writer.close()
except Exception:
pass
super().close()
class SocketHandler(Handler):
"""java.util.logging.SocketHandler"""
def __init__(self, host, port):
super().__init__()
self._host = host
self._port = port
self._sock = None
self._output_stream = None
def connect(self):
import socket
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.connect((self._host, self._port))
self._output_stream = self._sock.makefile("wb")
def publish(self, record):
if not self.isLoggable(record):
return
if self._output_stream is None:
try:
self.connect()
except Exception as e:
self.reportError("Cannot connect", e, ErrorManager.OPEN_FAILURE)
return
try:
msg = self.getFormatter().format(record)
self._output_stream.write(msg.encode() + b"\n")
self.flush()
except Exception as e:
self.reportError("Error sending record", e, ErrorManager.WRITE_FAILURE)
def flush(self):
if self._output_stream is not None:
try:
self._output_stream.flush()
except Exception:
pass
def close(self):
self.flush()
if self._output_stream is not None:
try:
self._output_stream.close()
except Exception:
pass
if self._sock is not None:
try:
self._sock.close()
except Exception:
pass
super().close()
class MemoryHandler(Handler):
"""java.util.logging.MemoryHandler"""
def __init__(self, target=None, size=1000, push_level=Level.SEVERE):
super().__init__()
self._target = target
self._size = size
self._push_level = push_level
self._buffer = []
def publish(self, record):
if not self.isLoggable(record):
return
self._buffer.append(record)
if len(self._buffer) >= self._size:
self.push()
elif record.getLevel().intValue() >= self._push_level.intValue():
self.push()
def push(self):
if self._target is not None:
for rec in self._buffer:
self._target.publish(rec)
self._buffer.clear()
self._target.flush()
def flush(self):
self.push()
def close(self):
self.push()
if self._target is not None:
self._target.close()
super().close()
def setPushLevel(self, level):
self._push_level = level
def getPushLevel(self):
return self._push_level
def setTarget(self, target):
self._target = target
def getTarget(self):
return self._target
# ============================================================
# Logger
# ============================================================
class Logger(Stub):
"""java.util.logging.Logger"""
_loggers = {}
_root = None
_global_logger = None
def __init__(self, name, resource_bundle_name=None):
super().__init__()
self._name = name
self._resource_bundle_name = resource_bundle_name
self._level = None
self._parent = None
self._handlers = []
self._filter = None
self._use_parent_handlers = True
@staticmethod
def getGlobal():
if Logger._global_logger is None:
Logger._global_logger = Logger("global")
return Logger._global_logger
@staticmethod
def getLogger(name, resource_bundle_name=None):
if not name:
if Logger._root is None:
Logger._root = Logger("", resource_bundle_name)
return Logger._root
if name not in Logger._loggers:
logger = Logger(name, resource_bundle_name)
Logger._loggers[name] = logger
logger._parent = Logger.getLogger("", None)
return Logger._loggers[name]
def getName(self):
return self._name
def getParent(self):
return self._parent
def setParent(self, parent):
self._parent = parent
def setLevel(self, level):
self._level = level
def getLevel(self):
return self._level
def isLoggable(self, level):
if self._level is not None:
return level.intValue() >= self._level.intValue()
if self._parent is not None:
return self._parent.isLoggable(level)
return level.intValue() >= Level.INFO.intValue()
def addHandler(self, handler):
if handler not in self._handlers:
self._handlers.append(handler)
def removeHandler(self, handler):
if handler in self._handlers:
self._handlers.remove(handler)
def getHandlers(self):
return self._handlers
def setUseParentHandlers(self, use):
self._use_parent_handlers = use
def getUseParentHandlers(self):
return self._use_parent_handlers
def setFilter(self, filter_):
self._filter = filter_
def getFilter(self):
return self._filter
def getResourceBundle(self):
return None
def getResourceBundleName(self):
return self._resource_bundle_name
def log(self, level, msg_or_supplier, *args):
if isinstance(level, Level):
if self.isLoggable(level):
if callable(msg_or_supplier) and not args:
msg = msg_or_supplier()
else:
msg = msg_or_supplier
record = LogRecord(level, msg)
record.setLoggerName(self._name)
record.setParameters(args or None)
self._log(record)
else:
# log(LogRecord)
self._log(level)
def _log(self, record):
if self._filter is not None and not self._filter.isLoggable(record):
return
for handler in self._handlers:
if handler.isLoggable(record):
handler.publish(record)
if self._use_parent_handlers and self._parent is not None:
self._parent._log(record)
def severe(self, msg):
self.log(Level.SEVERE, msg)
def warning(self, msg):
self.log(Level.WARNING, msg)
def info(self, msg):
self.log(Level.INFO, msg)
def config(self, msg):
self.log(Level.CONFIG, msg)
def fine(self, msg):
self.log(Level.FINE, msg)
def finer(self, msg):
self.log(Level.FINER, msg)
def finest(self, msg):
self.log(Level.FINEST, msg)
def entering(self, source_class, source_method, param=None):
msg = f"ENTRY {source_class}.{source_method}"
if param is not None:
msg += f" {param}"
self.log(Level.FINER, msg)
def exiting(self, source_class, source_method, result=None):
msg = f"RETURN {source_class}.{source_method}"
if result is not None:
msg += f" {result}"
self.log(Level.FINER, msg)
def throwing(self, source_class, source_method, thrown):
record = LogRecord(Level.FINER, "THROW")
record.setLoggerName(self._name)
record.setSourceClassName(source_class)
record.setSourceMethodName(source_method)
record.setThrown(thrown)
self._log(record)
def logp(self, level, source_class, source_method, msg, *params):
if self.isLoggable(level):
record = LogRecord(level, msg)
record.setLoggerName(self._name)
record.setSourceClassName(source_class)
record.setSourceMethodName(source_method)
record.setParameters(params or None)
self._log(record)
def logrb(self, level, source_class, source_method, bundle_name, msg, *params):
if self.isLoggable(level):
record = LogRecord(level, msg)
record.setLoggerName(self._name)
record.setSourceClassName(source_class)
record.setSourceMethodName(source_method)
record.setResourceBundleName(bundle_name)
record.setParameters(params or None)
self._log(record)
@staticmethod
def getAnonymousLogger(resource_bundle_name=None):
logger = Logger("", resource_bundle_name)
return logger
# ============================================================
# LogManager
# ============================================================
class LogManager(Stub):
"""java.util.logging.LogManager"""
_singleton = None
def __init__(self):
super().__init__()
self._loggers = {}
self._properties = {}
@staticmethod
def getLogManager():
if LogManager._singleton is None:
LogManager._singleton = LogManager()
return LogManager._singleton
def addLogger(self, logger):
name = logger.getName()
if name in self._loggers:
return False
self._loggers[name] = logger
return True
def getLogger(self, name):
return self._loggers.get(name)
def getLoggers(self):
return list(self._loggers.values())
def readConfiguration(self, input_stream=None):
pass
def readConfiguration(self, ins):
pass
def reset(self):
for logger in self._loggers.values():
for handler in logger.getHandlers()[:]:
handler.close()
logger.removeHandler(handler)
logger.setLevel(None)
def checkAccess(self):
pass
def addPropertyChangeListener(self, listener):
pass
def removePropertyChangeListener(self, listener):
pass
LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"
def getProperty(self, name):
return self._properties.get(name)
# ============================================================
# LoggingMXBean
# ============================================================
class LoggingMXBean(Stub):
"""java.util.logging.LoggingMXBean"""
def getLoggerLevel(self, logger_name):
logger = LogManager.getLogManager().getLogger(logger_name)
if logger and logger.getLevel():
return logger.getLevel().getName()
return ""
def setLoggerLevel(self, logger_name, level_name):
logger = LogManager.getLogManager().getLogger(logger_name)
if logger:
level = Level()
logger.setLevel(level.parse(level_name))
def getParentLogger(self, logger_name):
logger = LogManager.getLogManager().getLogger(logger_name)
if logger and logger.getParent():
return logger.getParent().getName()
return ""
def getLoggerNames(self):
return list(LogManager.getLogManager()._loggers.keys())
# ============================================================
# LoggingPermission
# ============================================================
class LoggingPermission(BasicPermission):
"""java.util.logging.LoggingPermission"""
def __init__(self, name, actions=None):
super().__init__(name, actions)
class IllegalArgumentException(RuntimeException):
"""java.lang.IllegalArgumentException"""
pass