Commit 9f5ad291 authored by Mario Hock's avatar Mario Hock

auto-logging implemented

parent 412a1b24
......@@ -94,6 +94,12 @@ class Measurement:
return ret
def get_begin(self):
return self.r1.timestamp
def get_end(self):
return self.r2.timestamp
def measure(interval = MEASUREMENT_INTERVAL):
......@@ -124,6 +130,7 @@ def main_loop():
# Set up (curses) UI.
ui.nics = nics
ui.nic_speeds = nic_speeds
ui.logging_manager = logging_manager
ui.init()
# Take an initial reading.
......@@ -141,9 +148,9 @@ def main_loop():
# Calculate the measurement from the last two readings.
measurement = Measurement(old_reading, new_reading)
# Display the measurement.
running = ui.display( measurement )
# Display/log the measurement.
running &= logging_manager.log(measurement)
running = ui.display( measurement )
# Store the last reading as |old_reading|.
old_reading = new_reading
......@@ -189,6 +196,8 @@ if __name__ == "__main__":
## Logging
parser.add_argument("-l", "--logging", action="store_true",
help="Enables logging.")
parser.add_argument("-A", "--autologging", action="store_true",
help="Enables auto-logging. (Log only on network activity. Implies --logging)")
parser.add_argument("-c", "--comment",
help="A comment that is stored in the logfile. (See --logging.)")
parser.add_argument("--path", default="/tmp/cpunetlog",
......@@ -224,8 +233,14 @@ if __name__ == "__main__":
hostname = osdetails[1]
## --autologging implies --logging
if ( args.autologging ):
args.logging = True
## Logging
logging_manager = LoggingManager( psutil.NUM_CPUS, monitored_nics, hostname, environment, args.comment, args.path )
logging_manager = LoggingManager( psutil.NUM_CPUS, monitored_nics, hostname, environment,
args.comment, args.path, args.autologging )
if args.logging:
logging_manager.enable_measurement_logger()
......
......@@ -23,12 +23,19 @@ divisor = 1000000.0
rounding_digits = 2
unit = "MBits"
LOGGING_STATE_COLORS = {"Active": 3, "Disabled": 1, "Standby": 4, "Enabled": 3}
## Reference to the logging manager, to display its state.
logging_manager = None
## GUI, positions of fields
LABEL_CPU_UTIL = 18
LABEL_CPU_USER = 48
LABEL_Sent = 18
LABEL_Received = 48
LABEL_CPU_UTIL = LABEL_Sent
LABEL_CPU_USER = LABEL_Received
LABEL_CPU_SYSTEM = 64
LABEL_Sent = LABEL_CPU_UTIL
LABEL_Received = LABEL_CPU_USER
## TODO ideas..
# - Add an option to set a fixed max. net-speed manually (for comparison)
......@@ -72,6 +79,16 @@ def _display_cpu_bar(y, x, cpu):
def _display_logging_state(y, x):
if ( not logging_manager ):
stdscr.addstr(y, x, 'Disabled', curses.A_BOLD)
else:
state = logging_manager.get_logging_state()
color = LOGGING_STATE_COLORS[state]
stdscr.addstr(y, x, state, curses.A_BOLD | curses.color_pair(color))
def init():
global stdscr
......@@ -101,6 +118,7 @@ def init():
curses.init_pair(4, curses.COLOR_YELLOW, -1) # "Total", (<cpu-system> ?)
curses.init_pair(5, curses.COLOR_CYAN, -1) # <cpu-system> / <cpu-other>
curses.init_pair(6, curses.COLOR_WHITE, -1) # <cpu-system> / <cpu-other>
curses.init_pair(7, curses.COLOR_RED, -1)
## Show some output to avoid upsetting the user
stdscr.addstr(3, 3, "loading ...", curses.A_BOLD)
......@@ -121,8 +139,10 @@ def display(measurement):
stdscr.border(0)
timenow = time.strftime("%H:%M:%S")
stdscr.addstr(1, 1, 'CPUnetLOG', curses.A_BOLD)
stdscr.addstr(1, LABEL_Sent, 'Time: {}'.format(timenow,), curses.A_BOLD)
stdscr.addstr(1, LABEL_Received, 'Interval: {}s'.format(round(measurement.timespan, 1)), curses.A_BOLD)
stdscr.addstr(1, LABEL_Sent, 'Time: {}'.format( timenow ), curses.A_BOLD)
stdscr.addstr(1, 39, 'Interval: {}s'.format( round(measurement.timespan, 1) ), curses.A_BOLD)
stdscr.addstr(1, 62, 'Logging: ', curses.A_BOLD)
_display_logging_state(1, 71)
stdscr.refresh()
y = 3
......
# -*- coding:utf-8 -*-
from collections import deque
class HistoryStore:
def __init__(self, history_size):
self.history_size = history_size
self.store = deque()
def push(self, element):
"""
Stores the new |element|.
The oldest element is popped from the store if |self.history_size| is exceeded.
In this case, the popped element is returned.
"""
self.store.append(element)
popped = None
if ( len(self.store) > self.history_size ):
popped = self.store.popleft()
return popped
def flush(self):
"""
Return all stored elements. (This removes the elements from the store.)
"""
ret = self.store
self.store = deque()
return ret
def size(self):
return len( self.store )
\ No newline at end of file
......@@ -4,6 +4,9 @@ import json
import time
import os
from history_store import HistoryStore
class LoggingClass:
def __init__(self, name, fields, siblings, description):
self.name = name
......@@ -248,7 +251,7 @@ class CNLFileWriter:
class LoggingManager:
def __init__(self, num_cpus, nics, hostname, environment, comment, path):
def __init__(self, num_cpus, nics, hostname, environment, comment, path, autologging):
self.num_cpus = num_cpus
self.nics = nics
self.comment = comment
......@@ -256,15 +259,38 @@ class LoggingManager:
self.hostname = hostname
self.environment = environment
# auto-logging
self.INACTIVITY_THRESHOLD = 30
self.HISTORY_SIZE = 30
self.auto_logging = autologging
if ( autologging ):
self.log_history = HistoryStore(self.HISTORY_SIZE)
self.logging_active = False
self.inactivity_count = 0
# "mkdir" on path, if necessary.
if ( path and not os.path.exists(path) ):
os.makedirs(path)
## Logger.
self.measurement_logger = None
self.measurement_logger_enabled = False
def enable_measurement_logger(self):
# Create filename from date.
t = time.time()
def _start_new_measurement_logger(self, measurement=None):
assert( not self.measurement_logger )
# find start time
if ( measurement ):
t = measurement.get_begin()
else:
t = time.time()
# Create filename from start time.
date = time.strftime("%Y-%m-%d_%H:%M:%S", time.localtime(t))
filename_prefix = self.path + "/" + date + "-" + self.hostname
filename = filename_prefix + ".cnl"
......@@ -280,17 +306,133 @@ class LoggingManager:
self.measurement_logger = MeasurementLogger(self.num_cpus, self.nics, [date,t],
self.hostname, self.environment, self.comment, filename)
self.measurement_logger_enabled = True
def _stop_measurement_logger(self):
print( "Logging stopped. File: " + self.measurement_logger.filename )
self.measurement_logger.close()
def log(self, measurement):
if ( self.measurement_logger_enabled ):
self.measurement_logger = None
def _is_activity_on_nics(self, measurement):
for nic in self.nics:
values = measurement.net_io[nic]
if ( values.ratio["bytes_sent"] > 0 or values.ratio["bytes_recv"] > 0 ):
return True
return False
def _log(self, measurement):
if ( self.measurement_logger ):
self.measurement_logger.log(measurement)
def _auto_logging_process_in_inactive_state(self, measurement):
## Store measurement.
self.log_history.push(measurement)
## If activity detected, start logging.
if ( self._is_activity_on_nics(measurement) ):
self.logging_active = True
self.inactivity_count = 0
## Create a new measurement logger (if enabled).
if ( self.measurement_logger_enabled ):
self._start_new_measurement_logger()
## Log the new measurement, but also some history.
for m in self.log_history.flush():
self._log(m)
def _auto_logging_process_in_active_state(self, measurement):
## Log measurement.
self._log(measurement)
## Branch: Inactive sample.
if ( not self._is_activity_on_nics(measurement) ):
self.inactivity_count += 1
## Inactivity phase too long: Stop logging.
if ( self.inactivity_count >= self.INACTIVITY_THRESHOLD ):
if ( self.measurement_logger_enabled ):
self._stop_measurement_logger()
self.logging_active = False
## Stop everything!! (XXX)
#return False ## TODO aktuell..
## Branch: Active sample.
else:
self.inactivity_count = 0
return True
def _auto_logging(self, measurement):
## BRANCH: Logging inactive,
# wait for activity on observed nics.
if ( not self.logging_active ):
self._auto_logging_process_in_inactive_state(measurement)
return True
## BRANCH: Logging active,
# log until observed nics get inactive.
else:
return self._auto_logging_process_in_active_state(measurement)
## Should be never reached.
assert( False )
def enable_measurement_logger(self):
self.measurement_logger_enabled = True
if ( not self.auto_logging ):
self._start_new_measurement_logger()
def log(self, measurement):
## BRANCH: no auto-logging, just call _log() directly.
if ( not self.auto_logging ):
self._log(measurement)
return True
## BRANCH: Auto-logging
else:
return self._auto_logging(measurement)
def get_logging_state(self):
if ( not self.measurement_logger_enabled ):
return "Disabled"
# BRANCH: no auto-logging
if ( not self.auto_logging ):
return "Enabled"
# BRANCH: auto-logging
else:
if ( self.logging_active ):
return "Active"
else:
return "Standby"
def close(self):
if ( self.measurement_logger_enabled ):
self.measurement_logger.close()
if ( self.measurement_logger ):
self._stop_measurement_logger()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment