以下是“Nginx实现浏览器可实时查看访问日志的步骤详解”的攻略。
步骤一:安装WebSocket模块
首先,我们需要在Nginx上安装WebSocket模块来实现实时查看访问日志的功能。WebSocket模块可以让我们建立与浏览器的长连接,从而实现实时推送日志信息到浏览器端。具体安装步骤如下:
- 打开Nginx的官网(https://nginx.org/)并从“Download”页面下载最新的Nginx源码压缩包。
- 解压缩该压缩包并进入解压后的文件夹。
- 在终端中输入以下命令:
./configure --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --add-module=path/to/nginx_http_push_module --add-module=path/to/nginx_http_websocket_module
make
sudo make install
其中, --add-module
后接的 path/to/nginx_http_push_module
和 path/to/nginx_http_websocket_module
是WebSocket模块的路径。
- 执行以上命令后,Nginx的WebSocket模块就已经安装完成了。
步骤二:修改配置文件
接下来,我们需要修改Nginx的配置文件。具体操作步骤如下:
- 打开Nginx的主配置文件(一般存放在
/usr/local/nginx/conf/nginx.conf
下),找到http
部分下的server
配置段。 - 向该配置段下添加以下内容:
access_log /var/log/nginx/access.log;
location = /real-time-log {
websocket_pass localhost:8080;
access_log off;
proxy_pass http://localhost:8080;
}
location /tail {
tail;
}
其中,access_log
配置项用于启用Nginx的访问日志,location
配置项用于定义WebSocket长连接地址(即 /real-time-log
),websocket_pass
配置项用于指定实时日志服务器的地址和端口,access_log off;
配置项用于关闭对实时日志 WebSocket 的访问日志记录,proxy_pass
配置项用于将 WebSocket 连接替换到 TCP 长连接上,tail
配置项表示启用tail模块,tail模块可以让我们查看访问日志的尾部。
- 然后在 http 部分中向
server
配置段下方添加以下内容:
location /logs {
alias /var/log/nginx/;
}
该配置项用于定义访问日志存放的路径,从而实现在浏览器中查看访问日志。
步骤三:重启Nginx
修改完配置文件后,需要重启Nginx使配置项生效。在终端中输入以下命令:
sudo /usr/local/nginx/sbin/nginx -s reload
步骤四:使用浏览器查看日志
完成以上步骤后,在浏览器中输入 http://localhost/logs
即可查看Nginx的访问日志,日志内容会自动更新并实时刷新,让我们实时追踪网站的访问情况。
示例一
以下是一个在Nginx配置中启用WebSocket模块和实时尾部tail模块的例子:
http {
upstream websocket_servers {
server 127.0.0.1:8000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
"" close;
}
server {
listen 80;
server_name www.example.com;
root PATH_TO_ROOT;
index index.html;
access_log /var/log/nginx/access.log;
location = /real-time-log {
internal;
proxy_pass http://websocket_servers;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /tail {
tail;
}
location / {
try_files $uri /index.html;
}
}
}
该配置文件中, WebSocket的 upstream 服务被配置为 127.0.0.1:8000 ,当访问日志发生时,该服务会推送给所有的连接。 实时的访问日志是在 location /real-time-log
中定义的。 /tail
是用来查看访问日志尾部的。当访问源 /logs
时, nginx会返回当前访问日志的目录。
示例二
以下是一个使用WebSocket实时推送Nginx访问日志的 Python 代码示例:
#!/usr/bin/env python3
import argparse
import asyncio
import json
import signal
import string
import sys
import time
import random
from aiohttp import web
import aiohttp
class WebSocketError(Exception):
pass
class RealTimeLog:
def __init__(self):
self.sockets = set()
async def __call__(self, request):
ws = web.WebSocketResponse(protocols=('chat',))
await ws.prepare(request)
self.sockets.add(ws)
try:
async for record in self.log():
for socket in self.sockets.copy():
await socket.send_str(json.dumps(record))
except WebSocketError:
pass
finally:
self.sockets.remove(ws)
return ws
async def log(self):
raise NotImplementedError()
class NginxLog(RealTimeLog):
def __init__(self, log_file='/var/log/nginx/access.log'):
super().__init__()
self._state = 'tail'
self._log_file = log_file
async def log(self):
cmd = f'tail -f {self._log_file}'
process = await asyncio.create_subprocess_shell(
cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
while True:
data = await process.stdout.readline()
if not data:
break
yield {
'state': self._state,
'log': data.decode(),
}
async def set_state(self, request):
self._state = await request.text()
async def on_shutdown(app):
for ws in app['websockets']:
await ws.close(code=aiohttp.WSCloseCode.GOING_AWAY,
message='Server shutdown')
async def websocket_handler(request):
ws = web.WebSocketResponse()
await ws.prepare(request)
app = request.app
app['websockets'].add(ws)
async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
if msg.data == 'tail':
await app['real_time_log'].set_state(msg)
continue
await ws.send_json({
'state': 'unknown',
'message': 'Unknown operation'
})
elif msg.type == aiohttp.WSMsgType.ERROR:
break
app['websockets'].remove(ws)
await ws.close()
return ws
async def real_time_log_factory(app, handler):
real_time_log = app['real_time_log'] = NginxLog('/var/log/nginx/access.log')
app.router.add_route('GET', '/real-time-log', real_time_log)
app.router.add_route('GET', '/websocket', handler)
return real_time_log
async def clk():
return int(time.time())
def attrs():
# Rotate the list.
# This means that the first round could have remote_addr on
# index 4 and second round on index 3 and so on.
for i in random.sample(range(len(string.ascii_letters)), len(string.ascii_letters)):
yield string.ascii_letters[i]
async def response(request):
ctime = await clk()
headers = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ0123456789 ,.:;{}[]()*&^^%$#@!~`'"
bodyattrs = ''.join(attrs())
headersattrs = ''.join(attrs())
data = "".join(
[headers[i % len(headers)] if i % 17 == 0 else bodyattrs[i % len(bodyattrs)]
for i in range(0, 1024)
]
)
return web.Response(body=data.encode(), headers={"X-Response-Time": str(ctime), headersattrs: headersattrs})
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Nginx Real-time log')
parser.add_argument('--port', type=int, default=8080,
help='Port to run web-server on')
parser.add_argument('--host', type=str, default='localhost',
help='Host to run web-server on')
args = parser.parse_args()
app = web.Application()
app['websockets'] = set()
app.router.add_route('GET', '/sample-response', response)
app.on_shutdown.append(on_shutdown)
real_time_log = app.loop.run_until_complete(
real_time_log_factory(app, websocket_handler))
app_runner = web.AppRunner(app)
app.addr = args.host
app.port = args.port
app.url = f"http://{app.addr}:{app.port}"
app.task = app.loop.create_task(aiohttp.web.run_app(app, host='localhost', port=args.port))
try:
app.loop.run_forever()
except KeyboardInterrupt as e:
pass
finally:
print("Exiting.")
sys.exit(0)
该代码中, RealTimeLog
类是一个抽象类, NginxLog
是对其的具体实现。它在父类 RealTimeLog
中实现了 WebSocket 连接的追踪和推送。在子类 NginxLog
中, 使用了 Tail
作为传入的文件。
attrs
生成用于改变响应体的属性和头部的随机字符串。 clk
生成用于将当前时间添加到头部中的时间戳。 response
使用了 attrs
方法和生成的时间。
调用函数中, 首先从参数解析器中提取参数。 app['websockets'] = set()
实例化一个全局的 socket 集合,其中, real_time_log
是从方法 real_time_log_factory
中获取的。后者通过 WebSocket 传输的数据由此生成,并且会一直在后台运行。
最后,通过aiohttp.web.run_app
方法开始将 app 对象转换为一个 HTTP 服务器。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Nginx实现浏览器可实时查看访问日志的步骤详解 - Python技术站