Skip to content

Instantly share code, notes, and snippets.

@evilkost
Created March 26, 2015 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evilkost/61b977458cd4949318f9 to your computer and use it in GitHub Desktop.
Save evilkost/61b977458cd4949318f9 to your computer and use it in GitHub Desktop.
class RedisLogHandler(Process):
"""
Single point to collect logs through redis pub/sub and write
them through standard python logging lib
"""
def __init__(self, opts):
Process.__init__(self, name="log_handler")
self.opts = opts
self.log_dir = os.path.dirname(self.opts.log_dir)
if not os.path.exists(self.log_dir):
os.makedirs(self.log_dir, mode=0o750)
self.components = ["spawner", "terminator",
"vmm", "job_grab", "backend"]
def setup_logging(self):
formatter = logging.Formatter(
'[%(asctime)s][%(levelname)6s][%(name)10s][%(pathname)s:%(funcName)s:%(lineno)d] %(message)s')
self.main_logger = logging.Logger("logger", level=logging.DEBUG)
self.main_handler = logging.handlers.WatchedFileHandler(
filename=os.path.join(self.log_dir, "logger.log"))
self.main_handler.setFormatter(formatter)
self.main_logger.addHandler(self.main_handler)
self.router_logger = logging.Logger("log_router")
self.router_logger.addFilter(CustomFilter())
for component in self.components:
handler = logging.handlers.WatchedFileHandler(
filename=os.path.join(self.log_dir, "{}.log".format(component)))
handler.setFormatter(formatter)
# 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)
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(event))
level = level_map[event.pop("level", "info")]
msg = event.pop("msg")
self.router_logger.log(level, msg, extra={"event": event})
except Exception as err:
self.main_logger.exception(err)
def run(self):
self.setup_logging()
setproctitle("RedisLogHandler")
rc = helpers.get_redis_connection(self.opts)
channel = rc.pubsub(ignore_subscribe_messages=True)
channel.subscribe(constants.LOG_PUB_SUB)
for raw in channel.listen():
if raw is not None and raw.get("type") == "message" and "data" in raw:
self.handle_msg(raw)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment