diff --git a/vnpy/trader/engine.py b/vnpy/trader/engine.py index a6f2da85..955e5263 100644 --- a/vnpy/trader/engine.py +++ b/vnpy/trader/engine.py @@ -1,11 +1,15 @@ """ """ +import logging +from datetime import datetime + from vnpy.event import EventEngine, Event from .event import EVENT_LOG from .object import LogData, SubscribeRequest, OrderRequest, CancelRequest - +from .utility import Singleton, get_temp_path +from .setting import SETTINGS class MainEngine: """ @@ -23,6 +27,8 @@ class MainEngine: self.gateways = {} self.apps = {} + self.log_engine = LogEngine(self, self.event_engine) + def write_log(self, msg: str): """ Put log event with specific message. @@ -31,7 +37,7 @@ class MainEngine: event = Event(EVENT_LOG, log) self.event_engine.put(event) - def get_gateway(gateway_name: str): + def get_gateway(self, gateway_name: str): """ Return gateway object by name. """ @@ -81,3 +87,71 @@ class MainEngine: gateway.close() self.event_engine.stop() + + +class LogEngine: + """ + Process log event and output with logging module. + """ + + __metaclass__ = Singleton + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + """""" + self.main_engine = main_engine + self.event_engine = event_engine + + if not SETTINGS["log.active"]: + return + + self.level = SETTINGS["log.level"] + self.logger = logging.getLogger("VN Trader") + self.formatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s") + + self.add_null_handler() + + if SETTINGS["log.console"]: + self.add_console_handler() + + if SETTINGS["log.file"]: + self.add_file_handler() + + self.register_event() + + def add_null_handler(self): + """ + Add null handler for logger. + """ + null_handler = logging.NullHandler() + self.logger.addHandler(null_handler) + + def add_console_handler(self): + """ + Add console output of log. + """ + console_handler = logging.StreamHandler() + console_handler.setLevel(self.level) + console_handler.setFormatter(self.formatter) + self.logger.addHandler(console_handler) + + def add_file_handler(self): + """ + Add file output of log. + """ + today_date = datetime.now().strftime("%Y%m%d") + filename = f"vt_{today_date}.log" + file_path = get_temp_path(filename) + + file_handler = logging.FileHandler(file_path, mode='w', encoding='utf8') + file_handler.setLevel(self.level) + file_handler.setFormatter(self.formatter) + self.logger.StreamHandler(file_handler) + + def register_event(self): + """""" + self.event_engine.register(EVENT_LOG, self.process_log_event) + + def process_log_event(self, event: Event): + """""" + log = event.data + self.logger.log(log.level, log.msg) \ No newline at end of file diff --git a/vnpy/trader/utility.py b/vnpy/trader/utility.py new file mode 100644 index 00000000..81b0f055 --- /dev/null +++ b/vnpy/trader/utility.py @@ -0,0 +1,35 @@ +""" +General utility functions. +""" + +from pathlib import Path + +class Singleton(type): + """ + Singleton metaclass, + + class A: + __metaclass__ = Singleton + + """ + _instances = {} + + def __call__(cls, *args, **kwargs): + """""" + if cls not in cls._instances: + cls._instances[cls] = super(VtSingleton, cls).__call__(*args, **kwargs) + + return cls._instances[cls] + + +def get_temp_path(filename): + """ + Get path for temp file with filename. + """ + home_path = Path.home() + temp_path = home_path.joinpath('.vntrader') + + if not temp_path.exists(): + temp_path.mkdir() + + return temp_path.joinpath(filename) \ No newline at end of file