日志记录

基本的日志记录

uWSGI中最基本的日志记录的形式是将请求、错误和信息消息写到标准输出/标准错误。这是默认配置中使用的方式。日志重定向的最基本的形式是 --logto / --logto2 / --daemonize 选项,它们允许你重定向日志到文件中。

基本记录日志到文件

要将日志写到文件中,而不是标准输出/标准错误,则使用 --logto ,或者同时守护uWSGI, --daemonize

./uwsgi -s :3031 -w simple_app --daemonize /tmp/mylog.log
./uwsgi -s :3031 -w simple_app --logto /tmp/mylog.log
# logto2 only opens the log file after privileges have been dropped to the specified uid/gid.
./uwsgi -s :3031 -w simple_app --uid 1001 --gid 1002 --logto2 /tmp/mylog.log

基本日志记录 (连接UDP模式)

使用UDP日志记录,你可以集中集群日志记录,或者重定向日志的持久化到其他机器上,以卸载磁盘I/O。UDP日志记录可以工作在守护模式和互动模式下。UDP日志记录是在连接socket模式下进行的,因此,UDP服务器必须在uWSGI启动前可用。对于更原始的方法(在未连接模式下工作),见socket日志记录部分。

要启用连接UDP模式,则传递UDP服务器的地址到 --daemonize/--logto 选项:

./uwsgi -s :3031 -w simple_app --daemonize 192.168.0.100:1717
./uwsgi -s :3031 -w simple_app --logto 192.168.0.100:1717

这将会重定向所有的标准输出/标准错误数据到192.168.0.100,端口1717上的UDP socket。现在,你需要一个UDP服务器,它将管理你的UDP消息。你可以使用netcat,甚至是uWSGI:

nc -u -p 1717 -s 192.168.0.100 -l
./uwsgi --udp 192.168.0.100:1717

第二种方式更有用一点,因为它将打印每条消息的来源 (ip:port)。在多个uWSGI服务器将日志记录在同一个UDP服务器上的情况下,它将让你区分服务器。当然,你可以编写你自己的应用来管理/过滤/保存通过UDP接收到的日志。

可插拔记录器

uWSGI还支持可插拔记录器,这让你在何处以及如何记录更具灵活性。取决于于你的uWSGI构建的配置,一些记录器可能/可能没有用。一些也许要求作为插件加载。要找出你的构建中哪些插件可用,请带 --logger-list 调用uWSGI。要设置一个可插拔记录器,则使用 --logger 或者 --req-logger 选项。 --logger 将为每条消息设置一个记录器,而 --req-logger 将会为请求信息消息设置一个记录器。

这是语法:

--logger <plugin>[:options]
--logger "<name> <plugin>[:options]" # The quotes are only required on the command line -- config files don't use them

只要你喜欢,你可以设置尽可能多的记录器。命名插件用于日志路由,下面是使用纯文本文件分割请求/错误日志记录的一个非常简单的例子。

[uwsgi]
req-logger = file:/tmp/reqlog
logger = file:/tmp/errlog

日志路由

默认情况下,所有的日志行会被发送到所有声明的记录器。如果你不想要这样,那么你可以使用 --log-route (以及用于请求记录器的 --log-req-route ),指定一个正则表达式来路由某些日志消息到不同的目的地。

例如:

[uwsgi]
logger = mylogger1 syslog
logger = theredisone redislog:127.0.0.1:6269
logger = theredistwo redislog:127.0.0.1:6270
logger = file:/tmp/foobar # This logger will log everything else, as it's not named
logger = internalservererror file:/tmp/errors
# ...
log-route = internalservererror (HTTP/1.\d 500)
log-route = mylogger1 uWSGI listen queue of socket .* full

这将会记录每个500错误到/tmp/errors,而监听队列满错误将会出现在/tmp/foobar中。这有点类似于 uWSGI告警子系统 (自1.3起) ,虽然告警通常更重,应该只用于紧急情况。

写日志到文件中

logfile 插件 —— 默认嵌入。

写日志到socket

logsocket 插件 —— 默认嵌入。

你可以使用 --logger socket:... (或者 --log-socket ...) 写日志到一个未连接UNIX/UDP socket。

uwsgi --socket :3031 --logger socket:/tmp/uwsgi.logsock

将会发送日志项到Unix socket /tmp/uwsgi.logsock.

uwsgi --socket :3031 --logger socket:192.168.173.19:5050

将会发送日志数据报到UDP地址192.168.173.19,端口是5050.你也可以通过传递多播地址,多播日志到多个日志服务器上:

uwsgi --socket :3031 --logger socket:225.1.1.1:1717

写日志到syslog

logsyslog 插件 —— 默认嵌入。

logsyslog 插件路由日志到Unix标准的syslog中。你可以传递一个用于发送的可选的ID,作为日志项的”facility”参数。
uwsgi --socket :3031 --logger syslog:uwsgi1234

或者

uwsgi --socket :3031 --logger syslog:uwsgi1234,local6

发送到local6 facility

写日志到远程syslog

logrsyslog 插件 —— 默认嵌入。

logrsyslog 插件路由日志到位于远程服务器的Unix标准syslog上。除了远程syslog服务器的address+port外,你可以传递一个用于发送的可选的ID,作为日志项的”facility”参数。

uwsgi --socket :3031 --logger rsyslog:12.34.56.78:12345,uwsgi1234

Redis记录器

redislog 插件 —— 默认嵌入。

默认情况下, redislog 插件将会“发布”每个日志行到一个redis pub/sub队列中。该记录器插件的语法如下:

--logger redislog[:<host>,<command>,<prefix>]

默认, host 会被映射到 127.0.0.1:6379command 会被映射到”publish uwsgi” 并且 prefix 是空的。要发布到一个名为foobar的队列,则使用 redislog:127.0.0.1:6379,publish foobar 。Redis日记记录不只限于pub/sub。例如,你可以推送项到一个列表中,如下所示。

--logger redislog:/tmp/redis.sock,rpush foo,example.com

当将一个日志行写入到一个远程服务器的时候,一个错误的场景会导致阻塞master,好的办法是使用 --threaded-logger 来卸载日志写入到第二个线程中。

MongoDB记录器

mongodblog 插件 —— 默认嵌入。.

MongoDB日志记录(mongodblog)的记录器语法是

--logger mongodblog[:<host>,<collection>,<node>]

其中, host 是MongoDB实例的地址 (默认 127.0.0.1:27017), collection 命名要写入日志行的集合 (默认是 uwsgi.logs),而 node 是用于实例发送日志的身份字符串 (默认是server hostname)。

--logger mongodblog

将会用默认值运行记录器,而

--logger mongodblog:127.0.0.1:9090,foo.bar

将会写入日志到mongodb服务器127.0.0.1:9090的集合 foo.bar 中,使用默认的节点名。就如Redis记录器一样,卸载日志写入到一个专用的线程是个好的选择。

[uwsgi]
threaded-logger = true
logger = mongodblog:127.0.0.1:27017,uwsgi.logs_of_foobar
# As usual, you could have multiple loggers:
# logger = mongodblog:192.168.173.22:27017,uwsgi.logs_of_foobar
socket = :3031

ZeroMQ日志记录

就如UDP日志记录一样,你可以通过ZeroMQ集中/分布日志记录。使用 ZMQ_PULL socket构建你的日志记录守护程序:

import zmq

ctx = zmq.Context()

puller = ctx.socket(zmq.PULL)
puller.bind("tcp://192.168.173.18:9191")

while True:
    message = puller.recv()
    print message,

现在,运行你的uWSGI服务器:

uwsgi --logger zeromq:tcp://192.168.173.18:9191 --socket :3031 --module werkzeug.testapp:test_app

(--log-zeromq 是这个记录器的一个别名。)

Crypto记录器 (插件)

如果你在云服务商托管你的应用,并且不使用持久化存储,那么你也许想要发送你的日志到一个外部系统。然而,日志通常包含敏感信息,并应该将那些信息明文传输。 logcrypto 插件记录器试图通过在发送之前加密每个日志包,然后通过UDP发送到一个能够解密它的服务器,从而解决这个问题。下一个例子将会发送每个日志包到192.168.173.22:1717上的一个UDP服务器,每个日志包都会用CBC模式中的Blowfish算法,通过密钥 ciaociao 进行加密。

uwsgi --plugin logcrypto --logger crypto:addr=192.168.173.22:1717,algo=bf-cbc,secret=ciaociao -M -p 4 -s :3031

一个样例服务器如下: https://github.com/unbit/uwsgi/blob/master/contrib/cryptologger.rb

Graylog2记录器 (插件)

graylog2 插件 —— 非默认编译。

这个插件将会发送日志的到一个Graylog2服务器上,使用Graylog2的原生GELF格式。

uwsgi --plugin graylog2 --logger graylog2:127.0.0.1:1234,dsfargeg

Systemd记录器 (插件)

systemd_logger 插件 —— 非默认编译。

这个插件将会将日志项写入到Systemd journal中。

uwsgi --plugin systemd_logger --logger systemd

编写你自己的日志记录插件

这个插件, foolog.c 将会把你的消息写入到由–logto/–daemonize指定的文件中,带有一个简单前缀,并使用vector IO。

#include <uwsgi.h>

ssize_t uwsgi_foolog_logger(struct uwsgi_logger *ul, char *message, size_t len) {

        struct iovec iov[2];

        iov[0].iov_base = "[foo] ";
        iov[0].iov_len = 6;

        iov[1].iov_base = message;
        iov[1].iov_len = len;

        return writev(uwsgi.original_log_fd, iov, 2);
}

void uwsgi_foolog_register() {
        uwsgi_register_logger("syslog", uwsgi_syslog_logger);
}

struct uwsgi_plugin foolog_plugin = {
    .name = "foolog",
    .on_load = uwsgi_foolog_register,
};