blob: 3c0e99d681877810ba19cfd3385abbec7ef4c93f [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import logging
from skywalking import config, agent
from skywalking.protocol.common.Common_pb2 import KeyStringValuePair
from skywalking.protocol.logging.Logging_pb2 import LogData, LogDataBody, TraceContext, LogTags, TextLog
from skywalking.trace.context import get_context
from skywalking.utils.exception import IllegalStateError
from skywalking.utils.filter import sw_traceback, sw_filter
def install():
from logging import Logger
layout = config.agent_log_reporter_layout # type: str
if layout:
from skywalking.log.formatter import SWFormatter
sw_formatter = SWFormatter(fmt=layout, tb_limit=config.agent_cause_exception_depth)
_handle = Logger.handle
log_reporter_level = logging.getLevelName(config.agent_log_reporter_level) # type: int
def _sw_handle(self, record):
_handle(self=self, record=record)
if self.disabled:
return
if record.name in ['skywalking', 'skywalking-cli', 'skywalking-loader']: # Ignore SkyWalking internal loggers
return
if record.levelno < log_reporter_level:
return
if not config.agent_log_reporter_ignore_filter and not self.filter(record): # ignore filtered logs
return
def build_log_tags() -> LogTags:
core_tags = [
KeyStringValuePair(key='level', value=str(record.levelname)),
KeyStringValuePair(key='logger', value=str(record.name)),
KeyStringValuePair(key='thread', value=str(record.threadName))
]
l_tags = LogTags()
l_tags.data.extend(core_tags)
if config.agent_log_reporter_formatted:
return l_tags
for i, arg in enumerate(record.args):
l_tags.data.append(KeyStringValuePair(key=f'argument.{str(i)}', value=str(arg)))
if record.exc_info:
l_tags.data.append(KeyStringValuePair(key='exception',
value=sw_traceback()
)) # \n doesn't work in tags for UI
return l_tags
context = get_context()
active_span_id = -1
primary_endpoint_name = ''
try:
# Try to extract active span, if user code/plugin code throws uncaught
# exceptions before any span is even created, just ignore these fields and
# avoid appending 'no active span' traceback that could be confusing.
# Or simply the log is generated outside any span context.
active_span_id = context.active_span.sid
primary_endpoint_name = context.primary_endpoint.get_name()
except IllegalStateError:
pass
log_data = LogData(
timestamp=round(record.created * 1000),
service=config.agent_name,
serviceInstance=config.agent_instance_name,
body=LogDataBody(
type='text',
text=TextLog(
text=sw_filter(transform(record))
)
),
tags=build_log_tags(),
)
if active_span_id != -1:
trace_context = TraceContext(
traceId=str(context.segment.related_traces[0]),
traceSegmentId=str(context.segment.segment_id),
spanId=active_span_id
)
log_data.traceContext.CopyFrom(trace_context)
if primary_endpoint_name:
log_data.endpoint = primary_endpoint_name
agent.archive_log(log_data)
Logger.handle = _sw_handle
def transform(record) -> str:
if config.agent_log_reporter_formatted:
if layout:
return sw_formatter.format(record=record)
newline = '\n'
return f"{record.getMessage()}{f'{newline}{sw_traceback()}' if record.exc_info else ''}"
return str(record.msg) # convert possible exception to str