0

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?

  • 1
    Does this answer your question? [How to group related request log entries GAE python 3.7 standard env](https://stackoverflow.com/questions/56113604/how-to-group-related-request-log-entries-gae-python-3-7-standard-env) – Samuel Romero Nov 14 '20 at 00:10
  • @SamuelRomero Thanks for your reply. I saw that post before but had another look at it. I now got it working. I added the solution in a separate answer. – Erik van den Hoorn Nov 16 '20 at 11:17

1 Answers1

0

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)