#1706 - Got the code services, application, and process base classes stubbed out. Need them now so that I can leverage them for core node services required.

This commit is contained in:
Chris McCarthy
2023-08-03 21:30:13 +01:00
parent cac4779244
commit 04f1cb0dc6
11 changed files with 378 additions and 82 deletions

View File

@@ -1,61 +0,0 @@
import logging
from pathlib import Path
class _JSONFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
"""Filter logs that start and end with '{' and '}' (JSON-like messages)."""
return record.getMessage().startswith("{") and record.getMessage().endswith("}")
class PCAP:
"""
A logger class for logging Frames as json strings.
This is essentially a PrimAITE simulated version of PCAP.
The PCAPs are logged to: <simulation output directory>/<hostname>/<hostname>_<ip address>_pcap.log
"""
def __init__(self, hostname: str, ip_address: str):
"""
Initialize the PCAP instance.
:param hostname: The hostname for which PCAP logs are being recorded.
:param ip_address: The IP address associated with the PCAP logs.
"""
self.hostname = hostname
self.ip_address = str(ip_address)
self._setup_logger()
def _setup_logger(self):
"""Set up the logger configuration."""
log_path = self._get_log_path()
file_handler = logging.FileHandler(filename=log_path)
file_handler.setLevel(60) # Custom log level > CRITICAL to prevent any unwanted standard DEBUG-CRITICAL logs
log_format = "%(message)s"
file_handler.setFormatter(logging.Formatter(log_format))
logger_name = f"{self.hostname}_{self.ip_address}_pcap"
self.logger = logging.getLogger(logger_name)
self.logger.setLevel(60) # Custom log level > CRITICAL to prevent any unwanted standard DEBUG-CRITICAL logs
self.logger.addHandler(file_handler)
self.logger.addFilter(_JSONFilter())
def _get_log_path(self) -> Path:
"""Get the path for the log file."""
root = Path(__file__).parent.parent.parent.parent.parent.parent / "simulation_output" / self.hostname
root.mkdir(exist_ok=True, parents=True)
return root / f"{self.hostname}_{self.ip_address}_pcap.log"
def capture(self, frame): # noqa Please don't make me, I'll have a circular import and cant use if TYPE_CHECKING ;(
"""
Capture a Frame and log it.
:param frame: The PCAP frame to capture.
"""
msg = frame.model_dump_json()
self.logger.log(level=60, msg=msg) # Log at custom log level > CRITICAL

View File

@@ -0,0 +1,37 @@
from abc import abstractmethod
from enum import Enum
from typing import List, Dict, Any
from primaite.simulator.system.software import Software
class ProcessOperatingState(Enum):
"""Enumeration of Process Operating States."""
RUNNING = 1
"The process is running."
PAUSED = 2
"The process is temporarily paused."
class Process(Software):
"""
Represents a Process, a program in execution, in the simulation environment.
Processes are executed by a Node and do not have the ability to performing input/output operations.
"""
operating_state: ProcessOperatingState
"The current operating state of the Process."
@abstractmethod
def describe_state(self) -> Dict:
"""
Describes the current state of the software.
The specifics of the software's state, including its health, criticality,
and any other pertinent information, should be implemented in subclasses.
:return: A dictionary containing key-value pairs representing the current state of the software.
:rtype: Dict
"""
pass

View File

@@ -1,87 +0,0 @@
import logging
from pathlib import Path
class _NotJSONFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
"""Filter logs that do not start and end with '{' and '}'."""
return not record.getMessage().startswith("{") and not record.getMessage().endswith("}")
class SysLog:
"""
A simple logger class for writing the sys logs of a Node.
Logs are logged to: <simulation output directory>/<hostname>/<hostname>_sys.log
"""
def __init__(self, hostname: str):
"""
Initialize the SysLog instance.
:param hostname: The hostname for which logs are being recorded.
"""
self.hostname = hostname
self._setup_logger()
def _setup_logger(self):
"""Set up the logger configuration."""
log_path = self._get_log_path()
file_handler = logging.FileHandler(filename=log_path)
file_handler.setLevel(logging.DEBUG)
log_format = "%(asctime)s %(levelname)s: %(message)s"
file_handler.setFormatter(logging.Formatter(log_format))
self.logger = logging.getLogger(f"{self.hostname}_sys_log")
self.logger.setLevel(logging.DEBUG)
self.logger.addHandler(file_handler)
self.logger.addFilter(_NotJSONFilter())
def _get_log_path(self) -> Path:
"""Get the path for the log file."""
root = Path(__file__).parent.parent.parent.parent.parent.parent / "simulation_output" / self.hostname
root.mkdir(exist_ok=True, parents=True)
return root / f"{self.hostname}_sys.log"
def debug(self, msg: str):
"""
Log a debug message.
:param msg: The message to log.
"""
self.logger.debug(msg)
def info(self, msg: str):
"""
Log an info message.
:param msg: The message to log.
"""
self.logger.info(msg)
def warning(self, msg: str):
"""
Log a warning message.
:param msg: The message to log.
"""
self.logger.warning(msg)
def error(self, msg: str):
"""
Log an error message.
:param msg: The message to log.
"""
self.logger.error(msg)
def critical(self, msg: str):
"""
Log a critical message.
:param msg: The message to log.
"""
self.logger.critical(msg)