already unpacked logs * started to disect log parsers for using streams in future * Qt Client started * logstream planned.
161 lines
5.7 KiB
Python
161 lines
5.7 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Monitor a StarConflict Log Directory.
|
|
"""
|
|
import sys, os
|
|
import time
|
|
import logging
|
|
from watchdog.observers import Observer
|
|
from watchdog.events import LoggingEventHandler
|
|
|
|
class SconEventHandler(LoggingEventHandler):
|
|
def __init__(self, monitor, *args, **kwargs):
|
|
self.monitor = monitor
|
|
return super(SconEventHandler, self).__init__(*args, **kwargs)
|
|
|
|
def on_moved(self, event):
|
|
super(SconEventHandler, self).on_moved(event)
|
|
if not event.is_directory:
|
|
self.monitor.close(event.src_path)
|
|
self.monitor.notify_event('moved', {'src': event.src_path,
|
|
'is_dir': event.is_directory,
|
|
'dest': event.dest_path})
|
|
|
|
def on_created(self, event):
|
|
super(SconEventHandler, self).on_created(event)
|
|
if not event.is_directory:
|
|
self.monitor.open(event.src_path)
|
|
self.monitor.notify_event('created', {'src': event.src_path,
|
|
'is_dir': event.is_directory})
|
|
|
|
def on_deleted(self, event):
|
|
super(SconEventHandler, self).on_deleted(event)
|
|
if not event.is_directory:
|
|
self.monitor.close(event.src_path)
|
|
self.monitor.notify_event('deleted', {'src': event.src_path,
|
|
'is_dir': event.is_directory})
|
|
|
|
def on_modified(self, event):
|
|
super(SconEventHandler, self).on_modified(event)
|
|
self.monitor.notify_event('modified', {'src': event.src_path,
|
|
'is_dir': event.is_directory})
|
|
|
|
|
|
|
|
class SconMonitor(object):
|
|
|
|
def notify(self, filename, lines):
|
|
# notify somebody, filename has a few lines.
|
|
# this is basicly the function you want to overwrite.
|
|
# @see: self.run for how to integrate monitor into your main loop.
|
|
if self.notifier is not None:
|
|
self.notifier.notify(filename, lines)
|
|
|
|
def notify_event(self, event_type, data):
|
|
if self.notifier is not None:
|
|
self.notifier.notify_event(event_type, data)
|
|
|
|
def __init__(self, path=None, notifier=None):
|
|
# if you initialize path directly, you lose success boolean.
|
|
# albeit atm. this is always true.
|
|
if path is not None:
|
|
self.initialize(path)
|
|
self.notifier = notifier
|
|
|
|
def initialize(self, path):
|
|
# initialize the monitor with a path to observe.
|
|
self.files = {}
|
|
self.event_handler = SconEventHandler(self)
|
|
self.observer = Observer()
|
|
self.observer.schedule(self.event_handler,
|
|
path,
|
|
recursive=True)
|
|
return True
|
|
|
|
def open(self, filename=None):
|
|
# open a logfile and add it to the read-list...
|
|
f = open(filename, 'r')
|
|
new_file = { 'file': f,
|
|
'cursor': f.tell() }
|
|
self.files[filename] = new_file
|
|
return new_file
|
|
|
|
def close(self, filename):
|
|
# close a single file by key, does not do anything if not found.
|
|
if filename in self.files.keys():
|
|
close_file = self.files.pop(filename)
|
|
close_file['file'].close()
|
|
del close_file
|
|
|
|
def close_all(self):
|
|
""" closes all open files in the monitor """
|
|
for key in self.files.keys():
|
|
self.close(key)
|
|
|
|
def read_line(self, afile):
|
|
# read a single line in a file.
|
|
f = afile.get('file', None)
|
|
if f is None:
|
|
return
|
|
afile['cursor'] = f.tell()
|
|
line = f.readline()
|
|
if not line:
|
|
f.seek(afile['cursor'])
|
|
return None
|
|
else:
|
|
return line
|
|
|
|
def do(self):
|
|
''' Monitor main task handler, call this in your mainloop in ~1 sec intervals '''
|
|
# read all file changes.
|
|
for key, value in self.files.items():
|
|
lines = []
|
|
data = self.read_line(value)
|
|
while data is not None:
|
|
lines.append(data)
|
|
data = self.read_line(value)
|
|
if lines:
|
|
self.notify(key, lines)
|
|
#
|
|
|
|
def initialize_loop(self):
|
|
''' initializes the main loop for the monitor '''
|
|
self.observer.start()
|
|
|
|
def break_loop(self):
|
|
''' call this if you want to break the monitors tasks '''
|
|
self.observer.stop()
|
|
|
|
def end_loop(self):
|
|
''' always call this before exiting your main loop '''
|
|
self.close_all()
|
|
self.observer.join()
|
|
|
|
def run(self):
|
|
''' Basic Standalone Main Loop implementation, do not call this in your app. '''
|
|
# if you want to run this on its own.
|
|
# everytime any logfile is updated, print it.
|
|
self.initialize_loop()
|
|
try:
|
|
while True:
|
|
self.do()
|
|
time.sleep(1)
|
|
except KeyboardInterrupt:
|
|
self.break_loop()
|
|
self.end_loop()
|
|
|
|
if __name__ == '__main__':
|
|
monitor = SconMonitor()
|
|
logging.basicConfig(level=logging.INFO,
|
|
format='%(asctime)s - %(message)s',
|
|
datefmt='%Y-%m-%d %H:%M:%S')
|
|
path = os.path.join(os.path.expanduser('~'),
|
|
'Documents',
|
|
'My Games',
|
|
'StarConflict',
|
|
'logs'
|
|
)
|
|
if monitor.initialize(path) is True:
|
|
monitor.run()
|
|
|