Merge pull request #5438 from chrismeyersfsu/private-performance_logging

add a new type of logger, performance.api
This commit is contained in:
Chris Meyers
2017-02-21 14:35:11 -05:00
committed by GitHub
4 changed files with 60 additions and 6 deletions

View File

@@ -41,6 +41,7 @@ __all__ = ['APIView', 'GenericAPIView', 'ListAPIView', 'SimpleListAPIView',
'DeleteLastUnattachLabelMixin',] 'DeleteLastUnattachLabelMixin',]
logger = logging.getLogger('awx.api.generics') logger = logging.getLogger('awx.api.generics')
analytics_logger = logging.getLogger('awx.analytics.performance')
def get_view_name(cls, suffix=None): def get_view_name(cls, suffix=None):
@@ -117,6 +118,8 @@ class APIView(views.APIView):
q_times = [float(q['time']) for q in connection.queries[queries_before:]] q_times = [float(q['time']) for q in connection.queries[queries_before:]]
response['X-API-Query-Count'] = len(q_times) response['X-API-Query-Count'] = len(q_times)
response['X-API-Query-Time'] = '%0.3fs' % sum(q_times) response['X-API-Query-Time'] = '%0.3fs' % sum(q_times)
analytics_logger.info("api response", extra=dict(python_objects=dict(request=request, response=response)))
return response return response
def get_authenticate_header(self, request): def get_authenticate_header(self, request):

View File

@@ -313,3 +313,13 @@ register(
category=_('Logging'), category=_('Logging'),
category_slug='logging', category_slug='logging',
) )
register(
'LOG_AGGREGATOR_TOWER_UUID',
field_class=fields.CharField,
allow_blank=True,
label=_('Cluster-wide Tower unique identifier.'),
help_text=_('Useful to uniquely identify Tower instances.'),
category=_('Logging'),
category_slug='logging',
default=None,
)

View File

@@ -2,7 +2,6 @@
# All Rights Reserved. # All Rights Reserved.
from logstash.formatter import LogstashFormatterVersion1 from logstash.formatter import LogstashFormatterVersion1
from django.conf import settings
from copy import copy from copy import copy
import json import json
import time import time
@@ -10,8 +9,11 @@ import time
class LogstashFormatter(LogstashFormatterVersion1): class LogstashFormatter(LogstashFormatterVersion1):
def __init__(self, **kwargs): def __init__(self, **kwargs):
settings_module = kwargs.pop('settings_module', None)
ret = super(LogstashFormatter, self).__init__(**kwargs) ret = super(LogstashFormatter, self).__init__(**kwargs)
self.host_id = settings.CLUSTER_HOST_ID if settings_module:
self.host_id = settings_module.CLUSTER_HOST_ID
self.tower_uuid = settings_module.LOG_AGGREGATOR_TOWER_UUID
return ret return ret
def reformat_data_for_log(self, raw_data, kind=None): def reformat_data_for_log(self, raw_data, kind=None):
@@ -56,6 +58,21 @@ class LogstashFormatter(LogstashFormatterVersion1):
adict[name] = subdict adict[name] = subdict
return adict return adict
def convert_to_type(t, val):
if t is float:
val = val[:-1] if val.endswith('s') else val
try:
return float(val)
except ValueError:
return val
elif t is int:
try:
return int(val)
except ValueError:
return val
elif t is str:
return val
if kind == 'job_events': if kind == 'job_events':
data.update(data.get('event_data', {})) data.update(data.get('event_data', {}))
for fd in data: for fd in data:
@@ -81,12 +98,32 @@ class LogstashFormatter(LogstashFormatterVersion1):
else: else:
data_for_log['facts'] = data data_for_log['facts'] = data
data_for_log['module_name'] = module_name data_for_log['module_name'] = module_name
elif kind == 'performance':
request = raw_data['python_objects']['request']
response = raw_data['python_objects']['response']
headers = [
(float, 'X-API-Time'), # may end with an 's' "0.33s"
(int, 'X-API-Query-Count'),
(float, 'X-API-Query-Time'), # may also end with an 's'
(str, 'X-API-Node'),
]
data_for_log['x_api'] = {k: convert_to_type(t, response[k]) for (t, k) in headers}
data_for_log['request'] = {
'method': request.method,
'path': request.path,
'path_info': request.path_info,
'query_string': request.META['QUERY_STRING'],
'data': request.data,
}
return data_for_log return data_for_log
def get_extra_fields(self, record): def get_extra_fields(self, record):
fields = super(LogstashFormatter, self).get_extra_fields(record) fields = super(LogstashFormatter, self).get_extra_fields(record)
if record.name.startswith('awx.analytics'): if record.name.startswith('awx.analytics'):
log_kind = record.name.split('.')[-1] log_kind = record.name[len('awx.analytics.'):]
fields = self.reformat_data_for_log(fields, kind=log_kind) fields = self.reformat_data_for_log(fields, kind=log_kind)
return fields return fields
@@ -104,9 +141,13 @@ class LogstashFormatter(LogstashFormatterVersion1):
# Extra Fields # Extra Fields
'level': record.levelname, 'level': record.levelname,
'logger_name': record.name, 'logger_name': record.name,
'cluster_host_id': self.host_id
} }
if getattr(self, 'tower_uuid', None):
message['tower_uuid'] = self.tower_uuid
if getattr(self, 'host_id', None):
message['cluster_host_id'] = self.host_id
# Add extra fields # Add extra fields
message.update(self.get_extra_fields(record)) message.update(self.get_extra_fields(record))

View File

@@ -116,7 +116,7 @@ class BaseHTTPSHandler(logging.Handler):
if not logger_name.startswith('awx.analytics'): if not logger_name.startswith('awx.analytics'):
# Tower log emission is only turned off by enablement setting # Tower log emission is only turned off by enablement setting
return False return False
return self.enabled_loggers is None or logger_name.split('.')[-1] not in self.enabled_loggers return self.enabled_loggers is None or logger_name[len('awx.analytics.'):] not in self.enabled_loggers
def emit(self, record): def emit(self, record):
""" """
@@ -189,7 +189,7 @@ def configure_external_logger(settings_module, async_flag=True, is_startup=True)
instance = None instance = None
if is_enabled: if is_enabled:
instance = BaseHTTPSHandler.from_django_settings(settings_module, async=async_flag) instance = BaseHTTPSHandler.from_django_settings(settings_module, async=async_flag)
instance.setFormatter(LogstashFormatter()) instance.setFormatter(LogstashFormatter(settings_module=settings_module))
awx_logger_instance = instance awx_logger_instance = instance
if is_enabled and 'awx' not in settings_module.LOG_AGGREGATOR_LOGGERS: if is_enabled and 'awx' not in settings_module.LOG_AGGREGATOR_LOGGERS:
awx_logger_instance = None awx_logger_instance = None