How to output Django log to Socket

Posted by john8675309 on Sun, 16 Jan 2022 20:28:56 +0100


This paper is a group[ 905329304 (my QQ water blowing group)], a big man asked a question I will share solutions to interesting problems. It is convenient for leaders to put forward their valuable opinions

Handlers

Intercepting the words in the document: the Handler is the engine that determines how to process each message in the logger. It describes specific logging behaviors, such as outputting messages to screens, files, or network socket s.

Based on this short passage, the problem was solved Then the next step is to find the corresponding Handlers and set them

Django only provides an AdminEmailHandler, which will report to the site for each log message received ADMINS Send an email. But the official introduction of Django doesn't say that messages can be output to the network socket

class AdminEmailHandler(include_html=False, email_backend=None, reporter_class=None)

SocketHandler

Sure enough Python 3 official documentation The corresponding for the response was found in SocketHandler , the official introduced it as follows: SocketHandler Class at logging.handlers modular. It can send log output to a network socket The base class uses TCP sockets.

class SocketHandler(host, port)

setting. Add configuration to PY

SocketHandler Two parameters need to be passed The parameter can be passed as long as it follows the class configuration You can see the socket key of handlers This is a custom name

LOGGING = {
    'version': 1,
    'handlers': {
        'socket': {
            'class': 'logging.handlers.SocketHandler',
            'host': "127.0.0.1",
            'port': 8848,
        }
    },
    'root': {
        'handlers': ['socket'],
    },
}

Server (receiver Demo)

Here is a simple Socket server. If you can't, you can refer to what I wrote before

Python hacker programming -- socket FoundationPython uses Socket to write an HTTP server from zeroPython uses Socket to write an HTTP server from zero (2), Python uses Socket to write an HTTP server from zero (3)

import socket

server = socket.socket()
server.bind(("127.0.0.1", 8848))
server.listen(5)
client, addr = server.accept()
print(client.recv(1024))

Add view Views

Add a view for testing to facilitate testing. Remember to add routes Not here

import logging

from django.http.response import JsonResponse


def index(request):
    print(logging)
    logging.error("Something is warning")
    return JsonResponse({"request": "ok!"})

test

Start Django service Open the Socket server Then visit the website in the browser. success

Custom Handler

Of course, you can also customize the Handler, as long as you inherit logging Just Handler We just need to implement the emit method

def emit(self, record):
    """
    Do whatever it takes to actually log the specified logging record.

    This version is intended to be implemented by subclasses and so
    raises a NotImplementedError.
    """
    raise NotImplementedError('emit must be implemented '
                              'by Handler subclasses')

This method will pass in a parameter record, which is a class under logging LogRecord , here is the meaning of common parameters (copied)

  • Name – the name of the recorder used to record the events represented by this LogRecord. Note that this name will always have this value, even if it may be issued by a handler attached to a different (ancestor) logger.
  • Level – the numeric level of the log event (one of DEBUG, INFO, etc.). Note that this will be converted to the two properties of LogRecord: the levelno value and the corresponding level name of levelname.
  • Pathname – the full pathname of the source file for the logging call.
  • lineno – the line number in the source file where the logging call is made.
  • msg – event description message, which may be a format string with variable data placeholders.
  • args – variable data to be merged into msg parameter to get event description.
  • exc_info – exception tuple with current exception information, or None if no exception information is available.
  • func – the name of the function or method called by the call logging.
  • sinfo – a text string representing stack information from the bottom of the stack in the current thread to the logging call.

In settings Py creates a file in the same directory, myhandler Py simply wrote a demo

from socket import socket
from logging import Handler, LogRecord


class SocketHandler(Handler):
    def __init__(self, host, port):
        Handler.__init__(self)
        self.host = host
        self.port = port
        if port is None:
            self.address = host
        else:
            self.address = (host, port)

    def emit(self, record: LogRecord) -> None:
        c = socket()
        c.connect(self.address)
        c.send(("[{}] {} {} \"{}\"".format(record.levelname, record.pathname, record.lineno, record.msg)).encode())
        c.close()

The same server Demo, modify settings Py configuration

LOGGING = {
    'version': 1,
    'handlers': {
        'socket': {
            'class': 'common.myHandler.SocketHandler',
            'host': "127.0.0.1",
            'port': 8848,
        }
    },
    'root': {
        'handlers': ['socket'],
    },
}

Data received successfully

Possible pit

Here are some problems (pits) I encountered in the process of use

ValueError: Unable to configure handler 'xxxx'

This error is an error when loading the logging configuration Here is a hint that there is an error, as shown in the figure

In fact, I have less configuration here. I need to pass in the parameters host and port. Therefore, when this error occurs, check whether the configuration is correct If it is a custom Handler, check whether there is an internal error

No processing logic entered

After the configuration, the desired effect was not achieved The following is the processing logic for demonstration

def emit(self, record: LogRecord) -> None:
    print('*-'*55)
    print(("[{}] {} {} \"{}\"".format(record.levelname, record.pathname, record.lineno, record.msg)).encode())

The request did not achieve the desired effect Or no logic at all

In the first case, the level of * * log events is not enough * *. In fact, I use info in my views, but I can notice that level is not set in my configuration Failed to capture the log

def index(request):
    print(logging)
    logging.info("Something is warning")
    return JsonResponse({"request": "ok!"})

My solution is to set the level directly to 0

The second case is Handlers are set but not used. Just add them to the following handlers

Topics: Django