Files
mongo/buildscripts/resmokelib/logging/jasper_logger.py

119 lines
4.8 KiB
Python

"""Jasper logging handlers and helpers."""
try:
import grpc
except ImportError:
pass
import logging
import os
import time
from buildscripts.resmokelib import config
from buildscripts.resmokelib import utils
def get_logger_config(group_id=None, test_id=None, process_name=None, prefix=None, trial=None):
# pylint: disable=too-many-locals
"""Return the jasper logger config."""
import jasper.jasper_pb2 as pb
username = os.getenv("CEDAR_USERNAME", default="")
api_key = os.getenv("CEDAR_API_KEY", default="")
test_id = utils.default_if_none(test_id, "")
process_name = utils.default_if_none(process_name, "")
prefix = utils.default_if_none(prefix, "")
trial = utils.default_if_none(trial, 0)
logger_config = pb.LoggerConfig()
log_level = pb.LogLevel(threshold=30, default=30)
log_format = pb.LogFormat.Value("LOGFORMATPLAIN")
if config.EVERGREEN_TASK_ID and group_id is not None:
buildlogger_info = pb.BuildloggerV3Info(
project=config.EVERGREEN_PROJECT_NAME, version=config.EVERGREEN_VERSION_ID,
variant=config.EVERGREEN_VARIANT_NAME, task_name=config.EVERGREEN_TASK_NAME,
task_id=config.EVERGREEN_TASK_ID, execution=config.EVERGREEN_EXECUTION,
test_name=str(test_id), proc_name=process_name, trial=trial, format=log_format, tags=[
str(group_id)
], prefix=prefix, base_address=config.CEDAR_URL, rpc_port=config.CEDAR_RPC_PORT,
username=username, api_key=api_key)
buildlogger_options = pb.BuildloggerV3Options(buildloggerv3=buildlogger_info,
level=log_level)
logger_config.buildloggerv3.CopyFrom(buildlogger_options)
else:
buffered = pb.BufferOptions()
base_opts = pb.BaseOptions(format=log_format, level=log_level, buffer=buffered)
log_opts = pb.DefaultLoggerOptions(prefix=prefix, base=base_opts)
logger_config.default.CopyFrom(log_opts)
return logger_config
class JasperHandler(logging.Handler):
"""Jasper logger handler."""
pb = None
rpc = None
def __init__(self, name, group_id, test_id=None):
"""Initialize the jasper handler.
The name uniquely identifies the logger within the logging cache. Group
id is required for cedar buildlogger, test id and trial are optional.
"""
logging.Handler.__init__(self)
self.name = "{}-{}".format(name, time.monotonic())
self.closed = False
logger_config = get_logger_config(group_id=group_id, test_id=test_id,
process_name=self.name)
output_opts = self.pb.OutputOptions(loggers=[logger_config])
create_args = self.pb.LoggingCacheCreateArgs(id=self.name, options=output_opts)
self.stub = self.rpc.JasperProcessManagerStub(
grpc.insecure_channel(config.JASPER_CONNECTION_STR))
try:
instance = self.stub.LoggingCacheCreate(create_args)
if not instance.outcome.success:
raise RuntimeError("Failed to setup jasper handler: {}".format(
instance.outcome.text))
except grpc.RpcError as rpc_err:
raise RuntimeError("Failed to setup jasper handler with status code {}: {}".format(
rpc_err.code(), rpc_err.details()))
def emit(self, record):
"""Emit a record to the jasper logging backend."""
record = self.format(record)
log_format = self.pb.LoggingPayloadFormat.Value("FORMATSTRING")
log_data = self.pb.LoggingPayloadData()
log_data.msg = record
logging_payload = self.pb.LoggingPayload(LoggerID=self.name, priority=40, format=log_format,
data=[log_data])
try:
outcome = self.stub.SendMessages(logging_payload)
if not outcome.success:
raise RuntimeError("Failed to send log message via jasper: {}".format(outcome.text))
except grpc.RpcError as rpc_err:
raise RuntimeError(
"Failed to send log message via jasper with status code {}: {}".format(
rpc_err.code(), rpc_err.details()))
def close(self):
"""Close the logging handler."""
logging.Handler.close(self)
if not self.closed:
self.closed = True
args = self.pb.LoggingCacheArgs(id=self.name)
try:
outcome = self.stub.LoggingCacheCloseAndRemove(args)
if not outcome.success:
raise RuntimeError("Failed to close jasper logger: {}".format(outcome.text))
except grpc.RpcError as rpc_err:
raise RuntimeError("Failed to close jasper logger with status code {}: {}".format(
rpc_err.code(), rpc_err.details()))