#!/usr/bin/python # -*- coding: GBK -*- """ Îļþ¹ÜÀíÄ£¿é ¸ºÔðÈÕÖ¾ÎļþµÄ´´½¨¡¢Ð´ÈëºÍ¹ÜÀí """ import os import time import datetime import threading from collections import namedtuple from packet_logger import packet_logger from clients_manager import ClientsMgr # ¶¨ÒåÎļþÐÅÏ¢Ôª×é FileInfo = namedtuple('FileInfo', ['server_id', 'event_type']) class FileWriteStats: """ÎļþдÈëͳ¼Æ""" def __init__(self): self.lock = threading.Lock() self.success_count = 0 self.fail_count = 0 def add_success(self): with self.lock: self.success_count += 1 def add_fail(self): with self.lock: self.fail_count += 1 def get_success_count(self): with self.lock: return self.success_count def get_fail_count(self): with self.lock: return self.fail_count def reset(self): with self.lock: self.success_count = 0 self.fail_count = 0 class WriteFile: """µ¥¸öÎļþдÈëÆ÷""" def __init__(self, filename, success_callback, fail_callback): self.filename = filename self.file_handle = None self.is_ready = False self.success_callback = success_callback self.fail_callback = fail_callback self.open_file() def open_file(self): """´ò¿ªÎļþ""" try: # È·±£Ä¿Â¼´æÔÚ dir_path = os.path.dirname(self.filename) if dir_path and not os.path.exists(dir_path): os.makedirs(dir_path) # ÒÔ×·¼Óģʽ´ò¿ªÎļþ self.file_handle = open(self.filename, 'ab') self.is_ready = True except Exception as e: self.is_ready = False print('[WriteFile] Failed to open file: %s, error: %s' % (self.filename, str(e))) def write_string(self, data): """дÈë×Ö·û´®Êý¾Ý""" if not self.is_ready: if self.fail_callback: self.fail_callback() return False try: # Ìí¼Ó Windows »»Ðзû²¢×ª»»Îª×Ö½Ú£¨¶þ½øÖÆÄ£Ê½£© line = (data + '\r\n').encode('gbk') self.file_handle.write(line) self.file_handle.flush() if self.success_callback: self.success_callback() return True except Exception as e: print('[WriteFile] Failed to write: %s, error: %s' % (self.filename, str(e))) self.is_ready = False if self.fail_callback: self.fail_callback() return False def close(self): """¹Ø±ÕÎļþ""" if self.file_handle: try: self.file_handle.close() except: pass self.file_handle = None self.is_ready = False def __del__(self): self.close() class FileMgr: """Îļþ¹ÜÀíÆ÷""" def __init__(self, config): self.config = config self.lock = threading.Lock() self.file_map = {} # FileInfo -> WriteFile self.stats = FileWriteStats() self.log_path = self.config.get_log_file_path() # È·±£ÈÕ־Ŀ¼´æÔÚ if not os.path.exists(self.log_path): try: os.makedirs(self.log_path) except Exception as e: print('[FileMgr] Failed to create log dir: %s, error: %s' % (self.log_path, str(e))) def get_instance(self, cid, event_type): """»ñÈ¡ÎļþдÈëʵÀý""" # »ñÈ¡¿Í»§¶ËServer ID clients_mgr = ClientsMgr.instance() server_id = clients_mgr.get_client_server_id(cid) if server_id == 0: packet_logger.log_text('FileMgr: WARNING - cid=%d has no server_id set! Defaulting to S0' % cid, 'WARN') file_info = FileInfo(server_id, event_type) with self.lock: # ¼ì²éÊÇ·ñÐèÒª´´½¨ÐÂÎļþ if file_info not in self.file_map: self._create_file_writer(file_info) else: write_file = self.file_map[file_info] if not self._check_file_valid(write_file, file_info): # ÎļþÎÞЧ,´´½¨ÐÂÎļþ write_file.close() del self.file_map[file_info] self._create_file_writer(file_info) return self.file_map[file_info] def _get_file_path(self, file_info): """»ñÈ¡Îļþ·¾¶""" write_mode = self.config.get_write_mode() # Îļþ¼ÐÃû³Æ: S + Server ID server_folder = 'S%d' % file_info.server_id folder_path = os.path.join(self.log_path, server_folder) # Ìí¼ÓÈÕÆÚ×ÓĿ¼: S1\2026-01-10 date_str = datetime.datetime.now().strftime('%Y-%m-%d') date_folder = os.path.join(folder_path, date_str) if write_mode == 1: # °´Ìì´æ´¢ filename = '%s_%s.txt' % (file_info.event_type, date_str) elif write_mode == 2: # °´Ð¡Ê±´æ´¢ date_time_str = datetime.datetime.now().strftime('%Y-%m-%d_%H') filename = '%s_%s.txt' % (file_info.event_type, date_time_str) elif write_mode == 3: # °´Îļþ´óС´æ´¢ date_time_str = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') filename = '%s_%s.txt' % (file_info.event_type, date_time_str) else: # µ¥¸öÎļþ filename = '%s.txt' % file_info.event_type return os.path.join(date_folder, filename) def _check_file_valid(self, write_file, file_info): """¼ì²éÎļþÊÇ·ñÓÐЧ(ÊÇ·ñÐèÒªÇл»)""" if not write_file.is_ready: return False write_mode = self.config.get_write_mode() # ¼ì²éÈÕÆÚ±ä»¯£¨ÊÊÓÃÓÚËùÓÐģʽ£© current_date = datetime.datetime.now().strftime('%Y-%m-%d') if current_date not in write_file.filename: return False if write_mode == 3: # °´Îļþ´óС¼ì²é max_size = self.config.get_max_file_size() * 1024 # KB -> Bytes try: file_size = os.path.getsize(write_file.filename) if file_size >= max_size: return False except: pass return True def _create_file_writer(self, file_info): """´´½¨ÎļþдÈëÆ÷""" filepath = self._get_file_path(file_info) write_file = WriteFile( filepath, self.stats.add_success, self.stats.add_fail ) self.file_map[file_info] = write_file def write_event(self, cid, event_type, event_data): """дÈëʼþÊý¾Ý""" write_file = self.get_instance(cid, event_type) return write_file.write_string(event_data) def get_success_count(self): """»ñÈ¡³É¹¦Ð´Èë´ÎÊý""" return self.stats.get_success_count() def get_fail_count(self): """»ñȡʧ°ÜдÈë´ÎÊý""" return self.stats.get_fail_count() def close_all(self): """¹Ø±ÕËùÓÐÎļþ""" with self.lock: for write_file in self.file_map.values(): write_file.close() self.file_map.clear()