| |
@@ -14,49 +14,6 @@
|
| |
from ..constants import default_log_format
|
| |
|
| |
|
| |
- level_map = {
|
| |
- "info": logging.INFO,
|
| |
- "debug": logging.DEBUG,
|
| |
- "error": logging.ERROR,
|
| |
- }
|
| |
-
|
| |
-
|
| |
- class LogRouterFilter(logging.Filter):
|
| |
- def __init__(self, who):
|
| |
- """
|
| |
- Value of field `who` which should be present to propagate LogRecord
|
| |
- """
|
| |
- super(LogRouterFilter, self).__init__()
|
| |
- self.who = who
|
| |
-
|
| |
- def filter(self, record):
|
| |
- return record.event.get("who") == self.who
|
| |
-
|
| |
-
|
| |
- class CustomFilter(logging.Filter):
|
| |
-
|
| |
- def filter(self, record):
|
| |
- if not hasattr(record, "event"):
|
| |
- return False
|
| |
-
|
| |
- event = record.event
|
| |
- if "traceback" in event:
|
| |
- record.msg = "{}\n{}".format(record.msg, event.pop("traceback"))
|
| |
-
|
| |
- # '%s %s' % (a, b) requires tuple, while
|
| |
- # json.loads(json.dumps(tuple)) returns array
|
| |
- if "args" in event and isinstance(event["args"], list):
|
| |
- event["args"] = tuple(event["args"])
|
| |
-
|
| |
- record.lineno = int(event.pop("lineno", "-1"))
|
| |
- record.funcName = event.pop("funcName", None)
|
| |
- record.pathname = event.pop("pathname", None)
|
| |
- for k, v in event.items():
|
| |
- setattr(record, k, v)
|
| |
-
|
| |
- return True
|
| |
-
|
| |
-
|
| |
class RedisLogHandler(object):
|
| |
"""
|
| |
Single point to collect logs through redis pub/sub and write
|
| |
@@ -81,43 +38,31 @@
|
| |
self.main_handler.setFormatter(default_log_format)
|
| |
self.main_logger.addHandler(self.main_handler)
|
| |
|
| |
- self.router_logger = logging.Logger("log_router")
|
| |
- self.router_logger.addFilter(CustomFilter())
|
| |
+ level = getattr(logging, self.opts.log_level.upper(), None)
|
| |
+ self.loggers = {}
|
| |
|
| |
for component in self.components:
|
| |
+ logger = logging.Logger(component)
|
| |
handler = logging.handlers.WatchedFileHandler(
|
| |
filename=os.path.join(self.log_dir, "{}.log".format(component)))
|
| |
handler.setFormatter(default_log_format)
|
| |
- handler.setLevel(level=level_map[self.opts.log_level])
|
| |
- # not very good from performance point:
|
| |
- # filter called for each message, but only one handler process record
|
| |
- # but it shouldn't be a real problem
|
| |
- handler.addFilter(filter=LogRouterFilter(component))
|
| |
- self.router_logger.addHandler(handler)
|
| |
+ handler.setLevel(level)
|
| |
+ logger.addHandler(handler)
|
| |
+ self.loggers[component] = logger
|
| |
|
| |
def handle_msg(self, raw):
|
| |
try:
|
| |
event = json.loads(raw["data"])
|
| |
|
| |
- # expected fields:
|
| |
- # - who: self.components
|
| |
- # - level: "info", "debug", "error", None --> default is "info"
|
| |
- # - msg: str with log msg
|
| |
- # [- traceback: str with error traceback ]
|
| |
- # [ more LogRecord kwargs, see: https://docs.python.org/2/library/logging.html#logrecord-objects]
|
| |
-
|
| |
- for key in ["who", "msg"]:
|
| |
- if key not in event:
|
| |
- raise Exception("Handler received msg without `{}` field, msg: {}".format(key, event))
|
| |
-
|
| |
- who = event["who"]
|
| |
- if who not in self.components:
|
| |
- raise Exception("Handler received msg with unknown `who` field: {}, msg: {}".format(who, event))
|
| |
-
|
| |
- level = level_map[event.pop("level", "info")]
|
| |
- msg = event.pop("msg")
|
| |
+ who = event.get('who', None)
|
| |
+ if not who:
|
| |
+ raise Exception("No LogRecord.who field, raw: {}".format(event))
|
| |
+ if who not in self.loggers:
|
| |
+ raise Exception("Unknown LogRecord.who field: {}, raw event: {}"
|
| |
+ .format(who, event))
|
| |
|
| |
- self.router_logger.log(level, msg, extra={"event": event})
|
| |
+ log_record = logging.makeLogRecord(event)
|
| |
+ self.loggers[who].handle(log_record)
|
| |
|
| |
except Exception as err:
|
| |
self.main_logger.exception(err)
|
| |