-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogpusher.py
More file actions
186 lines (147 loc) · 6.19 KB
/
Copy pathlogpusher.py
File metadata and controls
186 lines (147 loc) · 6.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import time
import configparser
import hashlib
import requests
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class LogEventHandler(FileSystemEventHandler):
"""日志文件变化事件处理器"""
def __init__(self, config, last_position=0):
self.config = config
self.last_position = last_position
self.wechat = WechatPusher(config)
def on_modified(self, event):
# 只处理配置中指定的日志文件
if not event.is_directory and event.src_path == self.config['log']['file_path']:
self.check_new_logs()
def check_new_logs(self):
"""检查并处理新的日志内容"""
try:
with open(self.config['log']['file_path'], 'r', encoding='utf-8') as f:
# 移动到上次读取的位置
f.seek(self.last_position)
# 读取新内容
new_content = f.read()
# 更新位置
self.last_position = f.tell()
if new_content:
self.process_new_logs(new_content)
except Exception as e:
print(f"读取日志文件出错: {str(e)}")
def process_new_logs(self, content):
"""处理新日志内容并决定是否推送"""
# 按行分割日志
lines = content.strip().split('\n')
# 检查是否包含需要推送的关键词
keywords = self.config['log']['keywords'].split(',') if self.config['log']['keywords'] else []
for line in lines:
# 如果有关键词配置,只推送包含关键词的日志
if keywords and not any(keyword in line for keyword in keywords):
continue
# 推送日志
self.push_log(line)
def push_log(self, log_content):
"""推送日志到指定用户"""
# 获取配置的用户列表
users = self.config['wechat']['users'].split(',')
# 推送消息给每个用户
for user in users:
if user.strip(): # 跳过空用户
result = self.wechat.send_text_message(user.strip(), f"【日志通知】\n{log_content}")
if result.get('errcode') == 0:
print(f"日志推送成功给用户 {user}")
else:
print(f"日志推送失败给用户 {user}: {result.get('errmsg')}")
class WechatPusher:
"""微信公众号推送工具类"""
def __init__(self, config):
self.appid = config['wechat']['appid']
self.appsecret = config['wechat']['appsecret']
self.access_token = None
self.token_expire_time = 0
def get_access_token(self):
"""获取访问令牌"""
# 检查token是否过期
if time.time() < self.token_expire_time:
return self.access_token
# 重新获取token
url = f"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={self.appid}&secret={self.appsecret}"
response = requests.get(url)
result = response.json()
if 'access_token' in result:
self.access_token = result['access_token']
self.token_expire_time = time.time() + result['expires_in'] - 300 # 提前5分钟过期
return self.access_token
else:
print(f"获取access_token失败: {result}")
return None
def send_text_message(self, openid, content):
"""发送文本消息给指定用户"""
access_token = self.get_access_token()
if not access_token:
return {'errcode': -1, 'errmsg': '未获取到access_token'}
url = f"https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={access_token}"
data = {
"touser": openid,
"msgtype": "text",
"text": {
"content": content
}
}
response = requests.post(url, json=data)
return response.json()
def load_config(config_file='config.ini'):
"""加载配置文件"""
config = configparser.ConfigParser()
config.read(config_file, encoding='utf-8')
# 检查必要的配置项
required_sections = ['wechat', 'log']
required_options = {
'wechat': ['appid', 'appsecret', 'users'],
'log': ['file_path']
}
for section in required_sections:
if not config.has_section(section):
raise ValueError(f"配置文件缺少必要的部分: {section}")
for option in required_options.get(section, []):
if not config.has_option(section, option):
raise ValueError(f"配置文件缺少必要的选项: {section}.{option}")
return config
def get_last_file_position(file_path):
"""获取文件最后位置,用于从上次结束的地方开始监控"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
f.seek(0, 2) # 移动到文件末尾
return f.tell()
except FileNotFoundError:
return 0
except Exception as e:
print(f"获取文件位置出错: {str(e)}")
return 0
def main():
try:
# 加载配置
config = load_config()
print("配置加载成功")
# 获取日志文件路径
log_file_path = config['log']['file_path']
# 获取日志文件当前位置(从这里开始监控新内容)
last_position = get_last_file_position(log_file_path)
# 创建事件处理器
event_handler = LogEventHandler(config, last_position)
# 创建观察者并开始监控
observer = Observer()
observer.schedule(event_handler, path=log_file_path, recursive=False)
observer.start()
print(f"开始监控日志文件: {log_file_path}")
# 保持程序运行
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
except Exception as e:
print(f"程序出错: {str(e)}")
if __name__ == "__main__":
main()