Skip to content

Instantly share code, notes, and snippets.

@Prof-Bloodstone
Forked from mariocesar/index.html
Last active January 17, 2021 11:56
Show Gist options
  • Save Prof-Bloodstone/e3c5feb1d32f0cc395b13631e278e6c6 to your computer and use it in GitHub Desktop.
Save Prof-Bloodstone/e3c5feb1d32f0cc395b13631e278e6c6 to your computer and use it in GitHub Desktop.
Example Python + Websockets to emulate tail -f
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Tail </title>
<style>
body {font-family: monospace;}
p{ margin: 0;}
ul{padding: 0;}
li{list-style:none; padding: 0; margin: 0;}
</style>
</head>
<body>
<ul id="logger">
</ul>
<script>
const socket = new WebSocket('ws://localhost:9000');
var log = document.getElementById('logger')
// Listen for messages
socket.addEventListener('message', function (event) {
var text = document.createTextNode(event.data)
var li = document.createElement("li")
li.appendChild(text)
log.prepend(li)
});
</script>
</body>
</html>
"""
We need websockets
pip install websockets
Run both servers:
python tail.py webserver /var/log/syslog
python tail.py tailserver /var/log/syslog
Go to http://127.0.0.1:8000
Test in linux by:
logger "this is a message"
"""
import sys
import asyncio
import websockets
from wsgiref.simple_server import make_server
loop = asyncio.get_event_loop()
options = {}
def line_offsets(file):
"""Seeks line offsets from file"""
start_loc = file.tell()
try:
file.seek(0)
# Read in the file once and build a list of line offsets
line_offset = []
offset = 0
for line in file:
line_offset.append(offset)
offset += len(line)
return line_offset
finally:
file.seek(start_loc) # Come back to the same spot
async def tail(websocket, path):
with open(options['path'], 'rt') as file:
seek = line_offsets(file)[-20]
sleep = None
while True:
file.seek(seek)
line = file.readline()
where = file.tell()
if line:
if seek != where:
sleep = None
await websocket.send(line.strip())
else:
sleep = 0.04
seek = where
if sleep:
await asyncio.sleep(sleep)
def wsgiapplication(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return open('index.html', 'rb')
def main(action):
if action == 'webserver':
with make_server('', 8000, wsgiapplication) as httpd:
print("Serving on port 8000...")
try:
httpd.serve_forever()
except KeyboardInterrupt:
httpd.shutdown()
elif action == 'tailserver':
tail_server = websockets.serve(tail, '', 9000)
loop.run_until_complete(tail_server)
loop.run_forever()
if __name__ == '__main__':
assert len(sys.argv) == 3, "Required at least two arguments, action and log path."
_, action, path = sys.argv
options['path'] = path
main(action)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment