I am trying to implement the method in this Stackoverflow answer to get my logs grouped by request and showing the highest severity level of the child logs on the request.
This is what I got so far:
custom_logger.py:
import inspect
import json
import os
from flask import g, request
from google.cloud import logging as gcp_logging
from google.cloud.logging.resource import Resource
LOG_LEVELS = ('DEFAULT', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
resource = Resource(type='gae_app',
labels={'project_id': os.environ['GOOGLE_CLOUD_PROJECT'],
'module_id': os.environ['GAE_SERVICE'],
'version_id': os.environ['GAE_VERSION']})
client = gcp_logging.Client()
custom_logger = client.logger('custom_logger')
request_logger = client.logger('request_logger')
def log_request(response):
trace_id = get_trace_id()
severity = LOG_LEVELS[g.get('log_level', 0)]
request_info = {
'requestMethod': request.method,
'requestUrl': request.url,
'status': response.status_code,
'userAgent': request.headers.get('USER-AGENT'),
'responseSize': response.content_length,
'latency': g.request_duration(),
'remoteIp': request.remote_addr
}
if request.method == 'POST':
payload = request.json() or json.loads(request.data.decode())
else:
payload = {}
request_logger.log_struct(payload,
trace=trace_id,
http_request=request_info,
severity=severity)
def default(text):
_log(text)
def log(text):
return default(text)
def debug(text, *args):
_log(text, *args)
def info(text, *args):
_log(text, *args)
def warning(text, *args):
_log(text, *args)
def warn(text, *args):
return warning(text, *args)
def error(text, *args):
_log(text, *args)
def critical(text, *args):
_log(text, *args)
def _log(text, *args):
trace_id = get_trace_id()
severity = inspect.stack()[1][3].upper()
new_level = LOG_LEVELS.index(severity)
previous_level = g.get('log_level', 0)
g.log_level = max(previous_level, new_level)
message = text % args
custom_logger.log_text(message, resource=resource,
severity=severity, trace=trace_id)
def get_trace_id():
return (f"projects/{os.environ['GOOGLE_CLOUD_PROJECT']}/traces/"
f"{request.headers['X-Cloud-Trace-Context'].split('/')[0]}")
main.py:
import json
import time
from flask import Flask, g, request, make_response
from flask_cors import CORS
import custom_logger as logging
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
@app.before_request
def setup_timing():
g.request_start_time = time.time()
g.request_duration = lambda: f'{(time.time() - g.request_start_time):.5f}s'
@app.after_request
def log_request(response):
logging.log_request(response)
return response
@app.route('/', methods=['GET', 'OPTIONS'])
def _test():
logger.debug('DEBUG %s', 'TEST')
logger.info('INFO %s', 'TEST')
logger.warning('WARNING %s', 'TEST')
logger.error('ERROR %s', 'TEST')
logger.critical('CRITICAL %s', 'TEST')
return 'Success'
It seems like the request_logger.log_struct function does not result in any entry being added to the logs. If I add a request_logger.log_text function before the request_logger.log_struct function then this does end up in the logs. Why do I not see the results of request_logger.log_struct in the logs?
After adding the "resource" property to the log_struct call in the log_request function I can see the requests in the "Logs viewer". The logs are now grouped and the highest severity level is added to the parent log entry.
request_logger.log_struct(payload,
resource=resource,
trace=trace_id,
http_request=request_info,
severity=severity)