吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3766|回复: 125
上一主题 下一主题
收起左侧

[原创工具] Windows服务监控工具

    [复制链接]
跳转到指定楼层
楼主
Thebzk 发表于 2025-3-6 08:52 回帖奖励
由于公司的OA服务器过于老旧,每隔几天OA的MYSQL服务就会自动停止,每次都要重启该服务才能正常使用OA,
为了解决这个问题,自制了一款Windows服务监控工具,当监控某个服务时,该服务异常停止后,该工具会自动重启
该服务。已测试一周,挺好用。

附上源码和软件
https://thebzk.lanzn.com/iNmoX2p37b6f
密码:f8ft


[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
import win32serviceutil
import win32service
import win32con
import time
import logging
import threading
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
from ttkbootstrap.scrolled import ScrolledText
from logging.handlers import RotatingFileHandler
import pystray
from PIL import Image, ImageDraw
import sys
 
class TextHandler(logging.Handler):
    def __init__(self, text_widget):
        super().__init__()
        self.text_widget = text_widget.text
 
    def emit(self, record):
        msg = self.format(record)
        def _append():
            try:
                self.text_widget.configure(state='normal')
                self.text_widget.insert(END, msg + '\n')
                self.text_widget.see(END)
                self.text_widget.configure(state='disabled')
            except Exception as e:
                print(f"日志写入失败: {str(e)}")
        self.text_widget.after(0, _append)
 
logger = logging.getLogger()
logger.setLevel(logging.INFO)
 
class ServiceMonitorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Windows服务监控程序 By:Thebzk")
        self.root.geometry("650x900")
        self.root.style.theme_use('litera')
        self.monitor_thread = None
        self.status_update_thread = None
        self.stop_event = threading.Event()
        self.monitored_services = []
        self.tray_icon = None
         
        self.init_tray_icon()
         
        self.root.protocol('WM_DELETE_WINDOW', self.on_close)
        self.root.bind("<Unmap>", self.on_minimize)
         
        self.CHECKED = "&#10003;"
        self.UNCHECKED = "&#9744;"
        self.FONT = ('Microsoft YaHei', 11)
         
        self.create_widgets()
        self.root.eval('tk::PlaceWindow . center')
 
    def init_tray_icon(self):
        image = Image.new('RGB', (64, 64), (255, 255, 255))
        dc = ImageDraw.Draw(image)
        dc.rectangle([16, 16, 48, 48], fill='#007bff')
         
        menu = (
            pystray.MenuItem('显示主界面', self.show_window),
            pystray.MenuItem('退出程序', self.exit_app)
        )
         
        self.tray_icon = pystray.Icon(
            "service_monitor",
            image,
            "服务监控程序",
            menu
        )
         
        self.tray_thread = threading.Thread(
            target=self.tray_icon.run,
            daemon=True
        )
        self.tray_thread.start()
 
    def create_widgets(self):
        main_paned = ttk.PanedWindow(self.root, bootstyle=PRIMARY, orient=VERTICAL)
        main_paned.pack(fill=BOTH, expand=True, padx=10, pady=10)
 
        top_frame = ttk.Frame(main_paned)
        main_paned.add(top_frame, weight=1)
 
        list_frame = ttk.Labelframe(top_frame, text="选择要监控的服务(点击复选框选择)", bootstyle=INFO)
        list_frame.pack(padx=5, pady=5, fill=BOTH, expand=True)
 
        self.service_tree = ttk.Treeview(
            list_frame,
            columns=("selected", "service_name", "status"),
            show="headings",
            bootstyle=INFO,
            height=10,
            selectmode='none'
        )
        style = ttk.Style()
        style.configure('Treeview',
            rowheight=40,
            font=self.FONT,
            padding=(0,5,0,5)
        )
        style.map('Treeview', background=[('selected', '#e0e0e0')])
         
        self.service_tree.heading("selected", text=" 选择 ", anchor=CENTER)
        self.service_tree.heading("service_name", text="服务名称")
        self.service_tree.heading("status", text="状态")
        self.service_tree.column("selected", width=100, anchor=CENTER)
        self.service_tree.column("service_name", width=350)
        self.service_tree.column("status", width=150, anchor=CENTER)
         
        scrollbar = ttk.Scrollbar(list_frame, bootstyle=ROUND, command=self.service_tree.yview)
        self.service_tree.configure(yscrollcommand=scrollbar.set)
        self.service_tree.pack(side=LEFT, fill=BOTH, expand=True)
        scrollbar.pack(side=RIGHT, fill=Y)
 
        self.service_tree.bind("<Button-1>", self.on_treeview_click)
 
        btn_frame = ttk.Frame(top_frame)
        btn_frame.pack(pady=15, fill=X)
 
        self.start_btn = ttk.Button(
            btn_frame,
            text="添加监控",
            command=self.add_monitoring,
            bootstyle=(SUCCESS, OUTLINE),
            width=12
        )
        self.start_btn.pack(side=LEFT, padx=10)
         
        ttk.Button(
            btn_frame,
            text="刷新列表",
            command=self.load_services,
            bootstyle=(INFO, OUTLINE),
            width=12
        ).pack(side=LEFT, padx=10)
         
        self.stop_btn = ttk.Button(
            btn_frame,
            text="停止监控",
            command=self.stop_monitoring,
            bootstyle=(DANGER, OUTLINE),
            state=DISABLED,
            width=12
        )
        self.stop_btn.pack(side=LEFT, padx=10)
 
        bottom_frame = ttk.Frame(main_paned)
        main_paned.add(bottom_frame, weight=1)
 
        monitored_frame = ttk.Labelframe(bottom_frame, text="已监控的服务列表", bootstyle=SUCCESS)
        monitored_frame.pack(padx=5, pady=5, fill=BOTH, expand=True)
 
        self.monitored_tree = ttk.Treeview(
            monitored_frame,
            columns=("service_name", "status"),
            show="headings",
            bootstyle=SUCCESS,
            height=10,
            selectmode='none'
        )
        self.monitored_tree.heading("service_name", text="服务名称")
        self.monitored_tree.heading("status", text="状态")
        self.monitored_tree.column("service_name", width=350)
        self.monitored_tree.column("status", width=180, anchor=CENTER)
         
        scrollbar_monitored = ttk.Scrollbar(monitored_frame, bootstyle=ROUND, command=self.monitored_tree.yview)
        self.monitored_tree.configure(yscrollcommand=scrollbar_monitored.set)
        self.monitored_tree.pack(side=LEFT, fill=BOTH, expand=True)
        scrollbar_monitored.pack(side=RIGHT, fill=Y)
 
        log_frame = ttk.Labelframe(self.root, text="监控日志", bootstyle=WARNING)
        log_frame.pack(padx=10, pady=10, fill=BOTH, expand=True)
 
        self.log_text = ScrolledText(
            log_frame,
            wrap=WORD,
            font=("Consolas", 10),
            height=8,
            autohide=True,
            bootstyle=ROUND
        )
        self.log_text.pack(fill=BOTH, expand=True)
 
        text_handler = TextHandler(self.log_text)
        text_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
        logger.addHandler(text_handler)
 
        self.status_update_thread = threading.Thread(target=self.update_all_service_statuses, daemon=True)
        self.status_update_thread.start()
 
        self.load_services()
 
    def on_treeview_click(self, event):
        region = self.service_tree.identify("region", event.x, event.y)
        if region == "cell":
            column = self.service_tree.identify_column(event.x)
            item = self.service_tree.identify_row(event.y)
            if column == "#1":
                current_value = self.service_tree.item(item, "values")[0]
                new_value = self.CHECKED if current_value == self.UNCHECKED else self.UNCHECKED
                values = list(self.service_tree.item(item, "values"))
                values[0] = new_value
                self.service_tree.item(item, values=values, tags=('checked' if new_value == self.CHECKED else 'unchecked'))
                self.service_tree.tag_configure('checked', foreground='#28a745')
                self.service_tree.tag_configure('unchecked', foreground='#6c757d')
 
    def load_services(self):
        self.service_tree.delete(*self.service_tree.get_children())
        try:
            services = self.list_services()
            for service in services:
                self.service_tree.insert("", END,
                    values=(self.UNCHECKED, service, "加载中"),
                    tags=('unchecked',)
                )
        except Exception as e:
            Messagebox.show_error(f"加载服务列表失败:{str(e)}", "错误", alert=True)
 
    def list_services(self):
        SC_MANAGER_CONNECT = 0x0001
        SC_MANAGER_ENUMERATE_SERVICE = 0x0004
        scm = win32service.OpenSCManager(None, None, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE)
        services = win32service.EnumServicesStatus(scm, win32service.SERVICE_WIN32, win32service.SERVICE_STATE_ALL)
        return [s[0] for s in services]
 
    def add_monitoring(self):
        selected_services = []
        for item in self.service_tree.get_children():
            values = self.service_tree.item(item, "values")
            if values[0] == self.CHECKED:
                service_name = values[1]
                if service_name not in self.monitored_services:
                    selected_services.append(service_name)
                    self.service_tree.item(item, values=(self.UNCHECKED, values[1], values[2]), tags=('unchecked',))
         
        if not selected_services:
            Messagebox.show_warning("请先勾选要添加的服务", "提示")
            return
 
        for service in selected_services:
            self.monitored_services.append(service)
            self.monitored_tree.insert("", END, values=(service, "监控中"))
            logger.info(f"新增监控服务: {service}")
 
        if not self.monitor_thread or not self.monitor_thread.is_alive():
            self.stop_event.clear()
            self.monitor_thread = threading.Thread(
                target=self.monitor_services,
                daemon=True
            )
            self.monitor_thread.start()
            self.stop_btn.configure(state=NORMAL)
 
    def monitor_services(self):
        while not self.stop_event.is_set():
            current_services = self.monitored_services.copy()
            if not current_services:
                time.sleep(1)
                continue
                 
            for service_name in current_services:
                try:
                    status = win32serviceutil.QueryServiceStatus(service_name)[1]
                    self.root.after(0, self.update_monitored_status, service_name, status)
                     
                    if status == win32service.SERVICE_STOPPED:
                        logger.warning(f"检测到服务停止: {service_name}")
                        win32serviceutil.StartService(service_name)
                        logger.info(f"已成功重启服务: {service_name}")
                except Exception as e:
                    logger.error(f"监控服务 {service_name} 时出错: {str(e)}")
            time.sleep(5)
 
    def update_monitored_status(self, service_name, status_code):
        status_text = self.get_status_text(status_code)
        for item in self.monitored_tree.get_children():
            values = self.monitored_tree.item(item, "values")
            if values[0] == service_name:
                self.monitored_tree.item(item, values=(service_name, status_text))
                break
 
    def update_all_service_statuses(self):
        while True:
            try:
                services = self.list_services()
                for service in services:
                    try:
                        status = win32serviceutil.QueryServiceStatus(service)[1]
                        status_text = self.get_status_text(status)
                        for item in self.service_tree.get_children():
                            values = self.service_tree.item(item, "values")
                            if values[1] == service:
                                self.service_tree.item(item, values=(values[0], service, status_text))
                                break
                    except Exception as e:
                        pass
            except Exception as e:
                logger.error(f"更新服务状态出错: {str(e)}")
            time.sleep(5)
 
    def get_status_text(self, status_code):
        status_map = {
            win32service.SERVICE_STOPPED: "已停止",
            win32service.SERVICE_START_PENDING: "启动中",
            win32service.SERVICE_STOP_PENDING: "停止中",
            win32service.SERVICE_RUNNING: "运行中",
            win32service.SERVICE_CONTINUE_PENDING: "继续中",
            win32service.SERVICE_PAUSE_PENDING: "暂停中",
            win32service.SERVICE_PAUSED: "已暂停"
        }
        return status_map.get(status_code, "未知")
 
    def stop_monitoring(self):
        self.stop_event.set()
        self.monitored_services.clear()
        self.monitored_tree.delete(*self.monitored_tree.get_children())
        self.stop_btn.configure(state=DISABLED)
        logger.info("已停止所有服务监控")
 
    def on_minimize(self, event):
        if self.root.state() == 'iconic':
            self.hide_to_tray()
            return "break" 
 
    def on_close(self):
        if Messagebox.okcancel("确认退出", "确定要退出程序吗?"):
            self.exit_app()
 
    def hide_to_tray(self):
        self.root.withdraw()
        self.tray_icon.visible = True
        logger.info("程序已最小化到系统托盘")
 
    def show_window(self):
        self.tray_icon.visible = False
        self.root.deiconify()
        self.root.lift()
        self.root.focus_force()
        logger.info("恢复程序主界面")
 
    def exit_app(self):
        self.stop_monitoring()
        self.tray_icon.stop()
        self.root.destroy()
        logger.info("程序已正常退出")
        sys.exit(0)
 
if __name__ == "__main__":
    app = ttk.Window()
    monitor_app = ServiceMonitorApp(app)
    app.mainloop()

2.png (59.71 KB, 下载次数: 1)

监控后以及日志

监控后以及日志

1.png (42.47 KB, 下载次数: 0)

主界面

主界面

免费评分

参与人数 18吾爱币 +24 热心值 +16 收起 理由
soft404 + 1 + 1 谢谢@Thanks!
iceboy800 + 1 + 1 谢谢@Thanks!
jmxxzpc + 1 + 1 谢谢@Thanks!
weikwok + 1 + 1 谢谢@Thanks!
52tc007 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
搞点什么 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ql4321 + 1 + 1 我很赞同!
明月相照 + 1 + 1 谢谢@Thanks!
你的小猫猫 + 1 + 1 谢谢@Thanks!
beatone + 1 热心回复!
q164741384 + 1 + 1 我很赞同!
koogg + 2 + 1 谢谢@Thanks!
coliuer + 1 + 1 膜拜大佬
449219454 + 1 用心讨论,共获提升!
bqi153 + 1 + 1 谢谢@Thanks!
lzy13 + 1 + 1 谢谢@Thanks!
macolma + 1 谢谢@Thanks!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 #
thp2008 发表于 2025-3-9 20:51
本帖最后由 thp2008 于 2025-3-12 11:30 编辑

感谢楼主的无私分享,受你的启发,我重新写了一个,功能更全一些的。
在以下方面进行优化,配置的灵活性,界面

1、可以搜索服务
2、添加服务监控时,可以选择动作,如果启动就停止或者如果停卡就启动。
3、可以导出备份某个时间的服务名称与状态、和启动类型,隔一段时间后,可以加载之前的备份与现在实时的状态进行比较,查看差异,好,发现异常情况。
4、可以导出监控的服务配置,下次需要直接导入就可以了。
5、可以监控进程,也可以选择动作,如果启动就停止,或者,如果停止,则启动指定应用。也可以导出相关配置,下次导入可直接使用。
6、监控日志窗口,可弹出,单独显示,方便查看实时日志。

1.0 下载地址:
https://wwwv.lanzn.com/irPhY2q3c2xe

--------------------------------------------------------------------------------------------------------------------------------

应网友要求,增加了,定时重启,定时关机的功能:

支持,倒计时、指定时间、指定日期和时间、周期性计划,每周X+时间,每月X号+时间。进行重启或关机的操作。

周期性计划,重启电脑后,启动本软件会自动加载之前的周期性计划。单次计划,执行完,就没有了。全部都有日志记录。

版本号变更为2.0

监控Windows服务与进程及自动重启与关机工具2.0  下载地址:
https://wwwv.lanzn.com/iBCaF2q9tjvc

--------------------------------------------------------------------------------------------------------------------------------

采纳了网友建议,在添加监控进程的时,增加了自动获取系统进程列表,从列表中直接搜索,或浏览选择的方式。
添加进程时,可以选择手工添加或者从系统进程列表中选择。有新增截图,见下面。

使用进程管理需要注意,不要添加或选择,系统权限的进程,结束不了,权限不够,可能会崩溃。

监控Windows服务与进程及自动重启与关机工具2.1  下载地址:
https://wwwv.lanzn.com/iBfhI2qc51jg






























免费评分

参与人数 12吾爱币 +12 热心值 +10 收起 理由
cczyx + 1 我很赞同!
52tc007 + 2 + 1 热心回复!
mohan007 + 1 + 1 热心回复!
webdav01 + 1 + 1 我很赞同!
wuloveyou + 1 热心回复!
iiiiiicl + 1 我很赞同!
koogg + 2 + 1 我很赞同!
Thebzk + 1 + 1 我很赞同!
duikang911 + 1 + 1 用心讨论,共获提升!
guyang9264 + 1 + 1 我很赞同!
zhc637 + 1 + 1 谢谢@Thanks!
449219454 + 1 热心回复!

查看全部评分

沙发
xiangyuebj 发表于 2025-3-8 15:31
        感谢发布原创作品,吾爱破解论坛因你更精彩
3#
alan150116 发表于 2025-3-8 16:43
4#
bbqn 发表于 2025-3-8 16:52
支持共享,谢谢
5#
CCNC 发表于 2025-3-8 22:31
好工具 谢谢大佬分享
6#
sky036 发表于 2025-3-8 22:40
这个不错,谢谢
7#
SevenTeen9 发表于 2025-3-8 22:42
谢谢大佬分享
8#
aifhc 发表于 2025-3-8 22:45

支持共享,谢谢
9#
temp2005 发表于 2025-3-9 09:21
适用哪些server版本
10#
macolma 发表于 2025-3-9 09:23
感谢你的作品
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-3 01:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表