-
-
Notifications
You must be signed in to change notification settings - Fork 631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[V2-UI] Move logging to Rust #6817
Changes from all commits
4092375
b058789
9932a29
ddc5ef0
4ff6b29
06317de
555f3ca
6a366c9
7b4f5c0
85d93df
f1ac593
56ae211
c4c8e74
37631de
2b5b3ce
77a92f1
d315f97
7a03b51
e09128e
796761b
75f00b2
5cbb2f4
695f169
bb86453
118840b
9d84495
2a36fa0
3daa496
258b133
12bc7cf
8b53076
db253a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,12 +7,13 @@ | |
import logging | ||
import os | ||
import sys | ||
import time | ||
from collections import namedtuple | ||
from logging import FileHandler, Formatter, StreamHandler | ||
from logging import StreamHandler | ||
|
||
from future.moves.http import client | ||
|
||
from pants.base.exception_sink import ExceptionSink | ||
from pants.engine.native import Native | ||
from pants.util.dirutil import safe_mkdir | ||
|
||
|
||
|
@@ -42,13 +43,71 @@ def _maybe_configure_extended_logging(logger): | |
_configure_requests_debug_logging() | ||
|
||
|
||
def init_rust_logger(level): | ||
native = Native() | ||
levelno = get_numeric_level(level) | ||
native.init_rust_logging(levelno) | ||
|
||
|
||
def setup_logging_to_stderr(python_logger, level): | ||
""" | ||
We setup logging as loose as possible from the Python side, | ||
and let Rust do the filtering. | ||
""" | ||
native = Native() | ||
levelno = get_numeric_level(level) | ||
handler = create_native_stderr_log_handler(levelno, native, stream=sys.stderr) | ||
blorente marked this conversation as resolved.
Show resolved
Hide resolved
|
||
python_logger.addHandler(handler) | ||
# Let the rust side filter levels; try to have the python side send everything to the rust logger. | ||
python_logger.setLevel("TRACE") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this an attempt to tell python "Log everything", and let the rust side have control over filtering? If so, may be worth adding a comment to that effect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO? Could also live without this. |
||
|
||
|
||
def setup_logging_from_options(bootstrap_options): | ||
# N.B. quiet help says 'Squelches all console output apart from errors'. | ||
level = 'ERROR' if bootstrap_options.quiet else bootstrap_options.level.upper() | ||
return setup_logging(level, console_stream=sys.stderr, log_dir=bootstrap_options.logdir) | ||
native = Native() | ||
return setup_logging(level, console_stream=sys.stderr, log_dir=bootstrap_options.logdir, native=native) | ||
|
||
|
||
class NativeHandler(StreamHandler): | ||
|
||
def __init__(self, level, native=None, stream=None, native_filename=None): | ||
super(NativeHandler, self).__init__(stream) | ||
self.native = native | ||
self.native_filename = native_filename | ||
self.setLevel(level) | ||
|
||
def emit(self, record): | ||
self.native.write_log(self.format(record), record.levelno, "{}:pid={}".format(record.name, os.getpid())) | ||
|
||
def flush(self): | ||
self.native.flush_log() | ||
|
||
|
||
def setup_logging(level, console_stream=None, log_dir=None, scope=None, log_name=None): | ||
def create_native_pantsd_file_log_handler(level, native, native_filename): | ||
fd = native.setup_pantsd_logger(native_filename, get_numeric_level(level)) | ||
ExceptionSink.reset_interactive_output_stream(os.fdopen(os.dup(fd), 'a')) | ||
return NativeHandler(level, native, native_filename=native_filename) | ||
|
||
|
||
def create_native_stderr_log_handler(level, native, stream=None): | ||
try: | ||
native.setup_stderr_logger(get_numeric_level(level)) | ||
except Exception as e: | ||
print("Error setting up pantsd logger: {}".format(e), file=sys.stderr) | ||
raise e | ||
|
||
return NativeHandler(level, native, stream) | ||
|
||
|
||
# TODO This function relies on logging._checkLevel, which is private. | ||
# There is currently no good way to convert string levels to numeric values, | ||
# but if there is ever one, it may be worth changing this. | ||
def get_numeric_level(level): | ||
return logging._checkLevel(level) | ||
|
||
|
||
def setup_logging(level, console_stream=None, log_dir=None, scope=None, log_name=None, native=None): | ||
"""Configures logging for a given scope, by default the global scope. | ||
|
||
:param str level: The logging level to enable, must be one of the level names listed here: | ||
|
@@ -63,6 +122,7 @@ def setup_logging(level, console_stream=None, log_dir=None, scope=None, log_name | |
The '.' separator providing the scope hierarchy. By default the root logger is | ||
configured. | ||
:param str log_name: The base name of the log file (defaults to 'pants.log'). | ||
:param Native native: An instance of the Native FFI lib, to register rust logging. | ||
:returns: The full path to the main log file if file logging is configured or else `None`. | ||
:rtype: str | ||
""" | ||
|
@@ -88,43 +148,19 @@ def trace(self, message, *args, **kwargs): | |
for handler in logger.handlers: | ||
logger.removeHandler(handler) | ||
|
||
|
||
if console_stream: | ||
console_handler = StreamHandler(stream=console_stream) | ||
console_handler.setFormatter(Formatter(fmt='%(levelname)s] %(message)s')) | ||
console_handler.setLevel(level) | ||
logger.addHandler(console_handler) | ||
native_handler = create_native_stderr_log_handler(level, native, stream=console_stream) | ||
logger.addHandler(native_handler) | ||
|
||
if log_dir: | ||
safe_mkdir(log_dir) | ||
log_filename = os.path.join(log_dir, log_name or 'pants.log') | ||
file_handler = FileHandler(log_filename) | ||
|
||
class GlogFormatter(Formatter): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
LEVEL_MAP = { | ||
logging.FATAL: 'F', | ||
logging.ERROR: 'E', | ||
logging.WARN: 'W', | ||
logging.INFO: 'I', | ||
logging.DEBUG: 'D', | ||
TRACE: 'T' | ||
} | ||
|
||
def format(self, record): | ||
datetime = time.strftime('%m%d %H:%M:%S', time.localtime(record.created)) | ||
micros = int((record.created - int(record.created)) * 1e6) | ||
return '{levelchar}{datetime}.{micros:06d} {process} {filename}:{lineno}] {msg}'.format( | ||
levelchar=self.LEVEL_MAP[record.levelno], | ||
datetime=datetime, | ||
micros=micros, | ||
process=record.process, | ||
filename=record.filename, | ||
lineno=record.lineno, | ||
msg=record.getMessage() | ||
) | ||
|
||
file_handler.setFormatter(GlogFormatter()) | ||
file_handler.setLevel(level) | ||
logger.addHandler(file_handler) | ||
|
||
native_handler = create_native_pantsd_file_log_handler(level, native, log_filename) | ||
file_handler = native_handler | ||
logger.addHandler(native_handler) | ||
|
||
|
||
logger.setLevel(level) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure where this traceback prints, could you confirm that it's to a good place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For pantsd, it will probably print nowhere. For nopantsd it will print to
sys.stderr
. Given this is only logged when we've failed to write toout
, I don't think there's a better behaviour we can offer...