#!/usr/bin/env python3
"""
This file is part of the PAFFrontendSim.
The PAFFrontendSim is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3 as published by the Free Software Foundation.
The PAFFrontendSim is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with the PAFFrontendSim. If not, see https://www.gnu.org/licenses/.
"""
#############################################################################
# import libs
#############################################################################
import subprocess
import datetime
from copy import copy, deepcopy
from pathlib import Path
#############################################################################
# constants
#############################################################################
# Log-Class constants
_endMarker = " => " # label end-marker
_labelInter = "." # marker in between lables
_LabelLength = 15 # length of the initial label
_AddLabelLength = 10 # length of each nested label attached
_Scenarios = { # implemented output scenarios
# name USER FLOW DATA DEBUG WARN ERROR
'verbose' : [True, True, True, True, True, True ], # all output-messages
'quiet' : [False, False, False, False, False, True ], # only errors
'data' : [True, True, True, False, True, True ], # no debug-messages
'run' : [True, True, False, False, True, True ] # no debug-messages and no data statements but full program-flow (default scenario)
}
############################################################################
# classes
############################################################################
[docs]
class LogClass :
"""
Module to replace Pythons built-in print function with a more complex alternative.
Since the simulator consists of multiple modules, it is important to discern the origin of printed messages.
For this reason, messages printed by LogClass are preceeded by a header.
This header contains the name of the module producing the message as well as the object hierarchy.
Optionally all messages can be stored in .log-files.
There is a .log-file for each module as well as a global file with all messages.
Additionally each message has a type of importance.
The importance affects the color of the text (for example red for errors).
It is also relevant for the verbosity.
A low verbosity setting will only cause the most important messages to be printed.
"""
def __init__ ( self, label = "", logPath = None ):
self.label = "" # name of the calling task as ID
self.logList = [] # log of all outputs which have a line-feed at the end
self.USER_TYPE = "user" # User defined messages in the individual Apps (usually not used in Libs)
self.FLOW_TYPE = "flow" # statements documenting the work-flow of the program and the lib-method calls
self.DATA_TYPE = "data" # statements providing information on input or output data of methods or apps
self.DEBUG_TYPE = "debug" # all kinds of debugging messages
self.WARNING_TYPE = "warning" # all kinds of warning messages
self.ERROR_TYPE = "error" # error messages
self.message_type_dict = {
self.USER_TYPE : [True, '\033[0m' ], # default color
self.FLOW_TYPE : [True, '\033[92m'], # green
self.DATA_TYPE : [True, '\033[94m'], # blue
self.DEBUG_TYPE : [True, '\033[96m'], # cyan
self.WARNING_TYPE : [True, '\033[93m'], # yellow
self.ERROR_TYPE : [True, '\033[91m'] # red
}
self.setScenario()
self.logPath = logPath # flag if output should go into log
self.addLabel(label)
[docs]
def writelog(self, message, message_type):
"""
Write the message to the log files.
Parameters:
message (string): The content of the message
message_type (string): What kind of message it is, info, warning, error, etc.
"""
timeInUTC = datetime.datetime.now(datetime.timezone.utc) # Get the current time in UTC
with open(Path(self.logPath, self.label.replace(" ", "")+".log"), 'a') as f: # Write to dedicated log file
f.write( message + " (" + message_type + ")\n" ) # Include message and message_type (for color)
f.close()
with open(Path(self.logPath, "global.log"), 'a') as f : # Write to global log file
f.write( str(timeInUTC) + " " + self.label + _endMarker + message + " (" + message_type + ")\n" ) # Include time and label
f.close()
[docs]
def printOut ( self, Message, message_type = "user", noSpace = True, lineFeed = True ) :
"""
Class console output function.
Parameters :
Message (string): Message-text
message_type (string): What type of message "Message" is. User, Error, etc.
noSpace (boolean): print Class-name, otherwise only spces of the same length
lineFeed (boolean): print line-feed at the end of the line
"""
# determine end character
if lineFeed == True :
endChar = "\n"
else:
endChar = "\r"
# determine labeling and restrict it in length
if noSpace and ( len( self.label ) > 0 ) :
header = self.label + _endMarker
else :
header = self.label + _endMarker + " "
# check for verbose and output label and message
if self.message_type_dict[message_type][0] == True :
print('\033[90m' + header + self.message_type_dict[message_type][1] + Message+'\033[0m', end = endChar) # Print colored message
if (self.logPath != None) and (lineFeed == True):
self.writelog( Message, message_type)
[docs]
def addLabel ( self, cls = "" ) :
"""
Add additional label to the label list.
Parameters:
cls (object): Object of a class whose label should be added to the label
"""
if isinstance( cls, str ):
addLabel = cls
else:
addLabel = type(cls).__name__
if len( addLabel ) == 0 :
return
if len( self.label ) == 0 :
#self.label = addLabel
self.label = ( addLabel + " " * _LabelLength )[0:_LabelLength]
else :
#self.label += _labelInter + addLabel
self.label += _labelInter + ( addLabel + " " * _AddLabelLength )[0:_AddLabelLength]
[docs]
def setScenario ( self, Type = "" ) :
"""
Set predefined output scenarios.
Parameters:
Type (string): id-string of the output scenario (so far defined, see constant-definitions above)
"""
outputList = _Scenarios.get( Type, _Scenarios['run'] )
for idx, messageType in enumerate(self.message_type_dict) :
self.message_type_dict[ messageType ][0] = outputList[idx]