Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5b3d20f3f | |||
| 1400d1efdb | |||
| f8ea21072f | |||
| 3fdd9ec927 |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
php:
|
||||
image: php:7.4-fpm-alpine
|
||||
volumes:
|
||||
- ./www:/usr/share/nginx/html
|
||||
- ./www/php-fpm/www.conf:/usr/local/etc/php-fpm.d/www.conf
|
||||
command: >
|
||||
sh -c "apk add --no-cache $PHPIZE_DEPS && docker-php-ext-install mysqli pdo_mysql && apk del $PHPIZE_DEPS && php-fpm"
|
||||
|
||||
nginx:
|
||||
image: nginx:stable-alpine
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./www:/usr/share/nginx/html
|
||||
depends_on:
|
||||
- php
|
||||
# 使用nc探测tcp端口,不再用wget(wget不兼容fastcgi)
|
||||
command: ["/bin/sh", "-c", "until nc -z php 9000; do echo '等待php-fpm端口就绪...'; sleep 1; done; nginx -g 'daemon off;'"]
|
||||
@@ -0,0 +1,23 @@
|
||||
services:
|
||||
php:
|
||||
image: php:7.4-fpm-alpine
|
||||
user: "101:101"
|
||||
volumes:
|
||||
- ./www:/usr/share/nginx/html
|
||||
# 关键:覆盖fpm监听配置
|
||||
- ./www/php-fpm/www.conf:/usr/local/etc/php-fpm.d/www.conf
|
||||
# 直接apk安装mysqli,不编译,避免gcc全家桶
|
||||
command: >
|
||||
sh -c "apk add --no-cache php7.4-mysqli && php-fpm"
|
||||
|
||||
nginx:
|
||||
image: nginx:stable-alpine
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./www:/usr/share/nginx/html
|
||||
depends_on:
|
||||
- php
|
||||
# alpine自带wget等待php端口就绪
|
||||
command: ["/bin/sh", "-c", "until wget -q -T1 php:9000; do echo '等待php-fpm就绪...'; sleep 1; done; nginx -g 'daemon off;'"]
|
||||
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
php:
|
||||
image: php:7.4-fpm-alpine
|
||||
volumes:
|
||||
- ./www:/usr/share/nginx/html
|
||||
# 新增安装mysqli扩展
|
||||
command: >
|
||||
sh -c "docker-php-ext-install mysqli && docker-php-ext-enable mysqli && php-fpm"
|
||||
nginx:
|
||||
image: nginx:stable-alpine
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./www:/usr/share/nginx/html
|
||||
depends_on:
|
||||
- php
|
||||
@@ -0,0 +1,54 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm index.php;
|
||||
|
||||
# 开启Gzip全局压缩(文本类压缩60%-80%)
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 16k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
gzip_vary on;
|
||||
|
||||
# PHP统一解析 + 优化参数
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
|
||||
# PHP-FPM优化:减少等待超时
|
||||
fastcgi_connect_timeout 60s;
|
||||
fastcgi_send_timeout 60s;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffer_size 128k;
|
||||
fastcgi_buffers 4 128k;
|
||||
fastcgi_busy_buffers_size 256k;
|
||||
fastcgi_temp_file_write_size 256k;
|
||||
}
|
||||
|
||||
# 首页通用路由
|
||||
location / {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# api目录转发
|
||||
location /api/ {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# 静态资源统一长期缓存(图片、样式、脚本、字体合并规则)
|
||||
location ~* \.(jpg|jpeg|png|gif|webp|ico|css|js|woff|woff2|ttf)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# 禁止外部直接访问cache缓存目录,返回403
|
||||
location ^~ /cache/ {
|
||||
deny all;
|
||||
return 403;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm index.php;
|
||||
|
||||
# 统一PHP解析规则(所有目录下.php文件都交给php-fpm解析)
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
# 自动获取当前请求php文件真实路径,支持任意php文件
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# 前端静态页面、目录访问
|
||||
location / {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# /api 仅路由,不用重复配置php,上面正则会自动处理
|
||||
location /api/ {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm index.php;
|
||||
|
||||
# 开启Gzip全局压缩(文本类压缩60%-80%)
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 16k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
gzip_vary on;
|
||||
|
||||
# PHP统一解析 + 优化参数
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
|
||||
# PHP-FPM优化:减少等待超时
|
||||
fastcgi_connect_timeout 60s;
|
||||
fastcgi_send_timeout 60s;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffer_size 128k;
|
||||
fastcgi_buffers 4 128k;
|
||||
fastcgi_busy_buffers_size 256k;
|
||||
fastcgi_temp_file_write_size 256k;
|
||||
}
|
||||
|
||||
# 首页通用路由
|
||||
location / {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# api目录转发
|
||||
location /api/ {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# 静态资源专项缓存(头像、js、css、字体)
|
||||
location ~* \.(jpg|jpeg|png|gif|webp|ico)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
access_log off;
|
||||
}
|
||||
location ~* \.(js|css|woff|woff2|ttf)$ {
|
||||
expires 3d;
|
||||
add_header Cache-Control "public, max-age=259200";
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm index.php;
|
||||
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 16k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
gzip_vary on;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
fastcgi_connect_timeout 60s;
|
||||
fastcgi_send_timeout 60s;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffer_size 128k;
|
||||
fastcgi_buffers 4 128k;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# 静态资源长期缓存
|
||||
location ~* \.(jpg|jpeg|png|gif|webp|ico)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
access_log off;
|
||||
}
|
||||
location ~* \.(js|css|woff|woff2|ttf)$ {
|
||||
expires 3d;
|
||||
add_header Cache-Control "public, max-age=259200";
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm index.php;
|
||||
|
||||
# 开启Gzip压缩,提升页面加载速度
|
||||
gzip on;
|
||||
gzip_min_length 1k;
|
||||
gzip_buffers 4 16k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;
|
||||
gzip_vary on;
|
||||
|
||||
# PHP解析配置
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
|
||||
# 优化PHP连接超时、缓冲区
|
||||
fastcgi_connect_timeout 60s;
|
||||
fastcgi_send_timeout 60s;
|
||||
fastcgi_read_timeout 60s;
|
||||
fastcgi_buffer_size 128k;
|
||||
fastcgi_buffers 4 128k;
|
||||
fastcgi_busy_buffers_size 256k;
|
||||
fastcgi_temp_file_write_size 256k;
|
||||
}
|
||||
|
||||
# 首页通用路由
|
||||
location / {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# API目录
|
||||
location /api/ {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# 静态资源长期缓存(本地static目录js/css/图片)
|
||||
location ~* \.(jpg|jpeg|png|gif|webp|ico)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
access_log off;
|
||||
}
|
||||
location ~* \.(js|css|woff|woff2|ttf)$ {
|
||||
expires 3d;
|
||||
add_header Cache-Control "public, max-age=259200";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# 禁止访问缓存目录cache,防止外部直接下载缓存文件
|
||||
location ^~ /cache/ {
|
||||
deny all;
|
||||
return 403;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm index.php;
|
||||
|
||||
# 前端静态页面
|
||||
location / {
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
# PHP告警接口
|
||||
location /api {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/api/index.php;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
import poplib
|
||||
import ssl
|
||||
import email
|
||||
from email.header import decode_header
|
||||
import time
|
||||
import pymysql
|
||||
|
||||
# 关闭SSL校验,解决老Python握手重置
|
||||
#ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
# ========== 邮箱配置 自行修改 ==========
|
||||
MAIL_HOST = "pop.163.com"
|
||||
MAIL_PORT = 995
|
||||
MAIL_USER = "lyudream@163.com"
|
||||
MAIL_PWD = "DVZxyF5NKCkR6fL5"
|
||||
|
||||
# ========== 本地MariaDB配置 ==========
|
||||
DB_HOST = "127.0.0.1"
|
||||
DB_USER = "root"
|
||||
DB_PWD = "hp93000"
|
||||
DB_NAME = "alert_mail_stat"
|
||||
|
||||
# 解码邮件标题、正文
|
||||
def decode_str(s):
|
||||
value, charset = decode_header(s)[0]
|
||||
if charset:
|
||||
value = value.decode(charset)
|
||||
return value
|
||||
|
||||
# 获取邮件正文
|
||||
def get_email_content(msg):
|
||||
content = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
content_type = part.get_content_type()
|
||||
content_disposition = str(part.get("Content-Disposition"))
|
||||
if content_type == 'text/plain' and 'attachment' not in content_disposition:
|
||||
payload = part.get_payload(decode=True)
|
||||
charset = part.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
break
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
charset = msg.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
return content
|
||||
|
||||
# 简单解析告警关键字(适配Alertmanager中文邮件模板:告警名称、实例、级别)
|
||||
def parse_alert_info(text):
|
||||
alert_name = ""
|
||||
instance = ""
|
||||
severity = "unknown"
|
||||
lines = text.splitlines()
|
||||
for line in lines:
|
||||
if "告警名称" in line:
|
||||
alert_name = line.split(":")[-1].strip()
|
||||
if "实例" in line:
|
||||
instance = line.split(":")[-1].strip()
|
||||
if "级别" in line:
|
||||
s_val = line.split(":")[-1].strip()
|
||||
if s_val.lower() in ["critical", "严重"]:
|
||||
severity = "critical"
|
||||
elif s_val.lower() in ["warning", "警告"]:
|
||||
severity = "warning"
|
||||
return alert_name, instance, severity
|
||||
|
||||
# 主抓取逻辑
|
||||
def crawl_mail():
|
||||
# 连接数据库
|
||||
db = pymysql.connect(host=DB_HOST, user=DB_USER, password=DB_PWD, database=DB_NAME, charset='utf8mb4')
|
||||
cursor = db.cursor()
|
||||
|
||||
# 连接POP3邮箱
|
||||
pop_conn = poplib.POP3_SSL(MAIL_HOST, MAIL_PORT)
|
||||
pop_conn.user(MAIL_USER)
|
||||
pop_conn.pass_(MAIL_PWD)
|
||||
total_num, total_size = pop_conn.stat()
|
||||
print(f"当前邮箱总邮件数量: {total_num}")
|
||||
|
||||
if total_num == 0:
|
||||
print("暂无新邮件")
|
||||
pop_conn.quit()
|
||||
db.close()
|
||||
return
|
||||
|
||||
# 从最新一封开始遍历
|
||||
for idx in range(total_num, 0, -1):
|
||||
# 获取邮件原始内容
|
||||
resp, raw_lines, octet = pop_conn.retr(idx)
|
||||
raw_msg = b'\r\n'.join(raw_lines).decode('utf-8', errors='ignore')
|
||||
msg = email.message_from_string(raw_msg)
|
||||
|
||||
# 生成唯一标识去重
|
||||
mail_uid = msg.get("Message-ID", str(time.time()))
|
||||
|
||||
# 查重,避免重复入库
|
||||
cursor.execute("SELECT id FROM alert_log WHERE mail_uid=%s", (mail_uid,))
|
||||
if cursor.fetchone():
|
||||
print(f"邮件{idx}已存在数据库,跳过")
|
||||
continue
|
||||
|
||||
# 解析标题、发件人
|
||||
subject = decode_str(msg.get("Subject", ""))
|
||||
from_addr = msg.get("From", "")
|
||||
|
||||
# ===================== 临时关闭发件人过滤,全部邮件放行测试 =====================
|
||||
# if "prometheusalert" not in from_addr.lower():
|
||||
# print(f"邮件{idx}发件人不匹配,跳过,发件人:{from_addr}")
|
||||
# continue
|
||||
|
||||
# 调试打印所有邮件基础信息
|
||||
print("\n========================================")
|
||||
print(f"【调试】正在处理第 {idx} 封邮件")
|
||||
print(f"发件人:{from_addr}")
|
||||
print(f"邮件标题:{subject}")
|
||||
print("========================================")
|
||||
|
||||
# 正文解析告警字段
|
||||
body = get_email_content(msg)
|
||||
alert_name, instance, severity = parse_alert_info(body)
|
||||
if not alert_name:
|
||||
print(f"邮件{idx}未识别到【告警名称】关键字,跳过")
|
||||
continue
|
||||
|
||||
# 区分触发/恢复告警
|
||||
alert_type = 1
|
||||
if "恢复" in subject or "resolved" in subject.lower():
|
||||
alert_type = 2
|
||||
|
||||
now = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
sql = """
|
||||
INSERT INTO alert_log
|
||||
(mail_uid, alert_type, alert_name, instance, severity, starts_at, ends_at, content, receive_time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
cursor.execute(sql, (mail_uid, alert_type, alert_name, instance, severity, now, None, body, now))
|
||||
db.commit()
|
||||
print(f"入库成功 | 告警:{alert_name} 实例:{instance}")
|
||||
|
||||
pop_conn.quit()
|
||||
cursor.close()
|
||||
db.close()
|
||||
print("\n本次抓取全部完成")
|
||||
|
||||
if __name__ == "__main__":
|
||||
crawl_mail()
|
||||
@@ -0,0 +1,140 @@
|
||||
import poplib
|
||||
import ssl
|
||||
import email
|
||||
from email.header import decode_header
|
||||
import time
|
||||
import pymysql
|
||||
|
||||
# 关闭SSL校验,解决老Python握手重置
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
# ========== 邮箱配置 自行修改 ==========
|
||||
MAIL_HOST = "pop.163.com"
|
||||
MAIL_PORT = 995
|
||||
MAIL_USER = "lyudream@163.com"
|
||||
MAIL_PWD = "DVZxyF5NKCkR6fL5"
|
||||
|
||||
# ========== 本地MariaDB配置 ==========
|
||||
DB_HOST = "127.0.0.1"
|
||||
DB_USER = "root"
|
||||
DB_PWD = "hp93000"
|
||||
DB_NAME = "alert_mail_stat"
|
||||
|
||||
# 解码邮件标题、正文
|
||||
def decode_str(s):
|
||||
value, charset = decode_header(s)[0]
|
||||
if charset:
|
||||
value = value.decode(charset)
|
||||
return value
|
||||
|
||||
# 获取邮件正文
|
||||
def get_email_content(msg):
|
||||
content = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
content_type = part.get_content_type()
|
||||
content_disposition = str(part.get("Content-Disposition"))
|
||||
if content_type == 'text/plain' and 'attachment' not in content_disposition:
|
||||
payload = part.get_payload(decode=True)
|
||||
charset = part.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
break
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
charset = msg.get_charset()
|
||||
if charset is None:
|
||||
charset = 'utf-8'
|
||||
content = payload.decode(charset, errors='ignore')
|
||||
return content
|
||||
|
||||
# 简单解析告警关键字(适配Alertmanager中文邮件模板:告警名称、实例、级别)
|
||||
def parse_alert_info(text):
|
||||
alert_name = ""
|
||||
instance = ""
|
||||
severity = "unknown"
|
||||
lines = text.splitlines()
|
||||
for line in lines:
|
||||
if "告警名称" in line:
|
||||
alert_name = line.split(":")[-1].strip()
|
||||
if "实例" in line:
|
||||
instance = line.split(":")[-1].strip()
|
||||
if "级别" in line:
|
||||
s_val = line.split(":")[-1].strip()
|
||||
if s_val.lower() in ["critical", "严重"]:
|
||||
severity = "critical"
|
||||
elif s_val.lower() in ["warning", "警告"]:
|
||||
severity = "warning"
|
||||
return alert_name, instance, severity
|
||||
|
||||
# 主抓取逻辑
|
||||
def crawl_mail():
|
||||
# 连接数据库
|
||||
db = pymysql.connect(host=DB_HOST, user=DB_USER, password=DB_PWD, database=DB_NAME, charset='utf8mb4')
|
||||
cursor = db.cursor()
|
||||
|
||||
# 连接POP3邮箱
|
||||
pop_conn = poplib.POP3_SSL(MAIL_HOST, MAIL_PORT)
|
||||
pop_conn.user(MAIL_USER)
|
||||
pop_conn.pass_(MAIL_PWD)
|
||||
total_num, total_size = pop_conn.stat()
|
||||
print(f"当前邮箱总邮件数量: {total_num}")
|
||||
|
||||
if total_num == 0:
|
||||
print("暂无新邮件")
|
||||
pop_conn.quit()
|
||||
db.close()
|
||||
return
|
||||
|
||||
# 从最新一封开始遍历
|
||||
for idx in range(total_num, 0, -1):
|
||||
# 获取邮件原始内容
|
||||
resp, raw_lines, octet = pop_conn.retr(idx)
|
||||
raw_msg = b'\r\n'.join(raw_lines).decode('utf-8', errors='ignore')
|
||||
msg = email.message_from_string(raw_msg)
|
||||
|
||||
# 生成唯一标识去重
|
||||
mail_uid = msg.get("Message-ID", str(time.time()))
|
||||
|
||||
# 查重,避免重复入库
|
||||
cursor.execute("SELECT id FROM alert_log WHERE mail_uid=%s", (mail_uid,))
|
||||
if cursor.fetchone():
|
||||
continue
|
||||
|
||||
# 解析标题、发件人
|
||||
subject = decode_str(msg.get("Subject", ""))
|
||||
from_addr = msg.get("From", "")
|
||||
# 过滤非告警发件人(自行修改匹配你的Alertmanager发件地址)
|
||||
if "prometheusalert" not in from_addr.lower():
|
||||
continue
|
||||
|
||||
# 正文解析告警字段
|
||||
body = get_email_content(msg)
|
||||
alert_name, instance, severity = parse_alert_info(body)
|
||||
if not alert_name:
|
||||
print(f"邮件{idx}未识别到告警,跳过")
|
||||
continue
|
||||
|
||||
# 区分触发/恢复告警
|
||||
alert_type = 1
|
||||
if "恢复" in subject or "resolved" in subject.lower():
|
||||
alert_type = 2
|
||||
|
||||
now = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
sql = """
|
||||
INSERT INTO alert_log
|
||||
(mail_uid, alert_type, alert_name, instance, severity, starts_at, ends_at, content, receive_time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
cursor.execute(sql, (mail_uid, alert_type, alert_name, instance, severity, now, None, body, now))
|
||||
db.commit()
|
||||
print(f"入库成功 | 告警:{alert_name} 实例:{instance}")
|
||||
|
||||
pop_conn.quit()
|
||||
cursor.close()
|
||||
db.close()
|
||||
print("本次抓取完成\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
crawl_mail()
|
||||
@@ -0,0 +1,77 @@
|
||||
import poplib
|
||||
import ssl
|
||||
import email
|
||||
from email.header import decode_header
|
||||
|
||||
# SSL兼容修复
|
||||
try:
|
||||
ctx = ssl._create_unverified_context
|
||||
except:
|
||||
ctx = None
|
||||
if ctx:
|
||||
ssl._create_default_https_context = ctx
|
||||
|
||||
# ========= 修改这里你的邮箱信息 =========
|
||||
MAIL_HOST = "pop.163.com"
|
||||
MAIL_PORT = 995
|
||||
MAIL_USER = "lyudream@163.com"
|
||||
MAIL_PWD = "DVZxyF5NKCkR6fL5"
|
||||
|
||||
def decode_text(s):
|
||||
value, charset = decode_header(s)[0]
|
||||
if charset:
|
||||
value = value.decode(charset)
|
||||
return value
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== 开始连接pop.163.com:995 ===")
|
||||
try:
|
||||
pop = poplib.POP3_SSL(MAIL_HOST, MAIL_PORT)
|
||||
print("连接服务器成功,正在登录...")
|
||||
pop.user(MAIL_USER)
|
||||
pop.pass_(MAIL_PWD)
|
||||
print("登录邮箱成功!")
|
||||
|
||||
total, _ = pop.stat()
|
||||
print(f"邮箱共有邮件:{total} 封\n")
|
||||
if total == 0:
|
||||
print("邮箱无邮件")
|
||||
pop.quit()
|
||||
exit()
|
||||
|
||||
# 从最新邮件遍历
|
||||
for i in range(total, 0, -1):
|
||||
resp, lines, octet = pop.retr(i)
|
||||
msg_raw = b"\r\n".join(lines).decode("utf-8", errors="ignore")
|
||||
msg = email.message_from_string(msg_raw)
|
||||
|
||||
subject = decode_text(msg.get("Subject", ""))
|
||||
from_addr = msg.get("From", "")
|
||||
|
||||
# 取正文
|
||||
body = ""
|
||||
if msg.is_multipart():
|
||||
for part in msg.walk():
|
||||
t = part.get_content_type()
|
||||
disp = str(part.get("Content-Disposition"))
|
||||
if t == "text/plain" and "attachment" not in disp:
|
||||
payload = part.get_payload(decode=True)
|
||||
body = payload.decode("utf-8", errors="ignore")
|
||||
break
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
body = payload.decode("utf-8", errors="ignore")
|
||||
|
||||
print("========================================")
|
||||
print(f"第{i}封邮件")
|
||||
print(f"发件人:{from_addr}")
|
||||
print(f"标题:{subject}")
|
||||
print(f"正文内容:\n{body}")
|
||||
print("========================================\n")
|
||||
|
||||
pop.quit()
|
||||
print("全部读取完成")
|
||||
|
||||
except Exception as e:
|
||||
print("连接/登录失败,错误信息:")
|
||||
print(str(e))
|
||||
@@ -0,0 +1,205 @@
|
||||
nohup: ignoring input
|
||||
* Serving Flask app "webhook" (lazy loading)
|
||||
* Environment: production
|
||||
WARNING: This is a development server. Do not use it in a production deployment.
|
||||
Use a production WSGI server instead.
|
||||
* Debug mode: off
|
||||
* Running on http://0.0.0.0:909/ (Press CTRL+C to quit)
|
||||
10.150.117.190 - - [02/Jul/2026 14:34:17] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:34:17] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:34:17] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:34:17] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:35:51] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:35:51] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:35:51] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:35:51] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:38] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:42] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:42] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:42:48] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:41] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:43:56] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:11] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:11] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:11] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:44:18] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:45:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:56:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:56:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:56:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:56:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:56:36] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:56:46] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:58:57] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:59:12] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:59:12] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 14:59:12] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 17:28:04] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 19:23:43] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [02/Jul/2026 19:24:03] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [03/Jul/2026 12:30:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [03/Jul/2026 12:30:38] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [03/Jul/2026 15:19:43] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [03/Jul/2026 15:19:53] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 13:44:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 13:50:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 13:56:43] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 13:57:03] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 14:26:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 14:28:53] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 14:33:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [04/Jul/2026 14:33:38] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.44.16 - - [06/Jul/2026 09:36:01] "[33mGET / HTTP/1.1[0m" 404 -
|
||||
10.150.44.16 - - [06/Jul/2026 09:36:02] "[33mGET /favicon.ico HTTP/1.1[0m" 404 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:21:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:21:31] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:25:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:28:03] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:28:51] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:30:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:30:31] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 11:31:46] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 12:21:51] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 13:54:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 13:55:18] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:44:18] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:45:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:45:26] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:45:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:50:58] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:50:58] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:52:38] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:52:38] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:54:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:54:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:54:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 14:54:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:13:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:13:33] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:16:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:16:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:18:48] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:18:48] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:49:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 15:50:48] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 16:00:58] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 16:01:08] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [06/Jul/2026 17:22:05] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 09:42:58] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 09:43:38] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 09:46:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 09:46:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:11:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:11:28] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:13:08] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:13:08] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:23:58] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:24:43] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:25:18] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:29:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 10:50:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:21:01] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:24:13] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:24:23] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:37:21] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:37:31] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:43:43] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:44:06] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:44:43] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:45:03] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 11:46:03] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 12:12:58] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
10.150.117.190 - - [07/Jul/2026 12:13:48] "[37mPOST /alert HTTP/1.1[0m" 200 -
|
||||
@@ -0,0 +1,65 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import pymysql
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def get_db():
|
||||
return pymysql.connect(
|
||||
host="127.0.0.1",
|
||||
user="root",
|
||||
password="hp93000",
|
||||
database="alert_mail_stat",
|
||||
charset="utf8mb4"
|
||||
)
|
||||
|
||||
@app.route("/alert", methods=["POST"])
|
||||
def alert_receive():
|
||||
try:
|
||||
data = request.get_json()
|
||||
alerts = data.get("alerts", [])
|
||||
insert_num = 0
|
||||
update_num = 0
|
||||
db = get_db()
|
||||
cur = db.cursor()
|
||||
|
||||
for alert in alerts:
|
||||
fp = alert["fingerprint"]
|
||||
alert_name = alert["labels"].get("alertname", "")
|
||||
instance = alert["labels"].get("instance", "")
|
||||
severity = alert["labels"].get("severity", "warning")
|
||||
status = alert["status"]
|
||||
start_at = alert.get("startsAt", "")
|
||||
end_at = alert.get("endsAt")
|
||||
alert_type = 2 if status == "resolved" else 1
|
||||
content_str = str(alert)
|
||||
|
||||
# 1. 原有告警入库逻辑不变
|
||||
sql = """
|
||||
INSERT INTO alert_log(mail_uid,alert_type,alert_name,instance,severity,starts_at,ends_at,content,receive_time)
|
||||
VALUES(%s,%s,%s,%s,%s,%s,%s,%s,NOW())
|
||||
"""
|
||||
cur.execute(sql, (fp, alert_type, alert_name, instance, severity, start_at, end_at, content_str))
|
||||
insert_num += 1
|
||||
|
||||
# 2. 新增:同步监控规则,存在则置为启用1
|
||||
if alert_name:
|
||||
sync_rule_sql = """
|
||||
INSERT INTO monitor_rule (rule_name, status)
|
||||
VALUES (%s, 1)
|
||||
ON DUPLICATE KEY UPDATE status = 1
|
||||
"""
|
||||
cur.execute(sync_rule_sql, [alert_name])
|
||||
|
||||
db.commit()
|
||||
cur.close()
|
||||
db.close()
|
||||
return jsonify({"code": 200, "insert": insert_num, "update": update_num})
|
||||
|
||||
except Exception as e:
|
||||
if "db" in locals():
|
||||
db.rollback()
|
||||
db.close()
|
||||
return jsonify({"code": 500, "msg": str(e)}), 200
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=909, debug=False)
|
||||
@@ -0,0 +1,47 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import pymysql
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def get_db():
|
||||
return pymysql.connect(
|
||||
host="127.0.0.1",
|
||||
user="root",
|
||||
password="hp93000",
|
||||
database="alert_mail_stat",
|
||||
charset="utf8mb4"
|
||||
)
|
||||
|
||||
@app.route("/alert", methods=["POST"])
|
||||
def alert_in():
|
||||
raw = request.get_json()
|
||||
alerts = raw.get("alerts", [])
|
||||
add_cnt = 0
|
||||
db = get_db()
|
||||
cur = db.cursor()
|
||||
for alert in alerts:
|
||||
fp = alert["fingerprint"]
|
||||
alert_name = alert["labels"].get("alertname", "")
|
||||
instance = alert["labels"].get("instance", "")
|
||||
severity = alert["labels"].get("severity", "warning")
|
||||
status = alert["status"]
|
||||
start = alert.get("startsAt", "")
|
||||
end = alert.get("endsAt")
|
||||
type_val = 2 if status == "resolved" else 1
|
||||
|
||||
cur.execute("SELECT id FROM alert_log WHERE mail_uid=%s", (fp,))
|
||||
if cur.fetchone():
|
||||
continue
|
||||
sql = """
|
||||
INSERT INTO alert_log(mail_uid,alert_type,alert_name,instance,severity,starts_at,ends_at,content,receive_time)
|
||||
VALUES(%s,%s,%s,%s,%s,%s,%s,%s,NOW())
|
||||
"""
|
||||
cur.execute(sql, (fp, type_val, alert_name, instance, severity, start, end, str(alert)))
|
||||
add_cnt += 1
|
||||
db.commit()
|
||||
cur.close()
|
||||
db.close()
|
||||
return jsonify({"code": 200, "insert_count": add_cnt})
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=909, debug=False)
|
||||
@@ -0,0 +1,47 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import pymysql
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def get_db():
|
||||
return pymysql.connect(
|
||||
host="127.0.0.1",
|
||||
user="root",
|
||||
password="hp93000",
|
||||
database="alert_mail_stat",
|
||||
charset="utf8mb4"
|
||||
)
|
||||
|
||||
@app.route("/alert", methods=["POST"])
|
||||
def alert_receive():
|
||||
data = request.get_json()
|
||||
alerts = data.get("alerts", [])
|
||||
insert_num = 0
|
||||
db = get_db()
|
||||
cur = db.cursor()
|
||||
for alert in alerts:
|
||||
fp = alert["fingerprint"]
|
||||
alert_name = alert["labels"].get("alertname", "")
|
||||
instance = alert["labels"].get("instance", "")
|
||||
severity = alert["labels"].get("severity", "warning")
|
||||
status = alert["status"]
|
||||
start_at = alert.get("startsAt", "")
|
||||
end_at = alert.get("endsAt")
|
||||
alert_type = 2 if status == "resolved" else 1
|
||||
|
||||
cur.execute("SELECT id FROM alert_log WHERE mail_uid=%s", (fp,))
|
||||
if cur.fetchone():
|
||||
continue
|
||||
sql = """
|
||||
INSERT INTO alert_log(mail_uid,alert_type,alert_name,instance,severity,starts_at,ends_at,content,receive_time)
|
||||
VALUES(%s,%s,%s,%s,%s,%s,%s,%s,NOW())
|
||||
"""
|
||||
cur.execute(sql, (fp, alert_type, alert_name, instance, severity, start_at, end_at, str(alert)))
|
||||
insert_num += 1
|
||||
db.commit()
|
||||
cur.close()
|
||||
db.close()
|
||||
return jsonify({"code": 200, "insert": insert_num})
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=909, debug=False)
|
||||
@@ -0,0 +1,72 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import pymysql
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def get_db():
|
||||
return pymysql.connect(
|
||||
host="127.0.0.1",
|
||||
user="root",
|
||||
password="hp93000",
|
||||
database="alert_mail_stat",
|
||||
charset="utf8mb4"
|
||||
)
|
||||
|
||||
@app.route("/alert", methods=["POST"])
|
||||
def alert_receive():
|
||||
try:
|
||||
data = request.get_json()
|
||||
alerts = data.get("alerts", [])
|
||||
insert_num = 0
|
||||
update_num = 0
|
||||
db = get_db()
|
||||
cur = db.cursor()
|
||||
|
||||
for alert in alerts:
|
||||
fp = alert["fingerprint"]
|
||||
alert_name = alert["labels"].get("alertname", "")
|
||||
instance = alert["labels"].get("instance", "")
|
||||
severity = alert["labels"].get("severity", "warning")
|
||||
status = alert["status"]
|
||||
start_at = alert.get("startsAt", "")
|
||||
end_at = alert.get("endsAt")
|
||||
alert_type = 2 if status == "resolved" else 1
|
||||
content_str = str(alert)
|
||||
|
||||
cur.execute("""
|
||||
SELECT id FROM alert_log
|
||||
WHERE mail_uid=%s AND DATE(receive_time) = CURDATE()
|
||||
ORDER BY id DESC LIMIT 1
|
||||
""", (fp,))
|
||||
row = cur.fetchone()
|
||||
|
||||
if status == "resolved":
|
||||
if row:
|
||||
cur.execute("""
|
||||
UPDATE alert_log
|
||||
SET alert_type=%s, ends_at=%s, content=%s
|
||||
WHERE mail_uid=%s AND id=%s
|
||||
""", (alert_type, end_at, content_str, fp, row[0]))
|
||||
update_num += 1
|
||||
else:
|
||||
# 删掉唯一索引后,每次故障直接插入,不再判断是否存在
|
||||
sql = """
|
||||
INSERT INTO alert_log(mail_uid,alert_type,alert_name,instance,severity,starts_at,ends_at,content,receive_time)
|
||||
VALUES(%s,%s,%s,%s,%s,%s,%s,%s,NOW())
|
||||
"""
|
||||
cur.execute(sql, (fp, alert_type, alert_name, instance, severity, start_at, end_at, content_str))
|
||||
insert_num += 1
|
||||
|
||||
db.commit()
|
||||
cur.close()
|
||||
db.close()
|
||||
return jsonify({"code": 200, "insert": insert_num, "update": update_num})
|
||||
|
||||
except Exception as e:
|
||||
if "db" in locals():
|
||||
db.rollback()
|
||||
db.close()
|
||||
return jsonify({"code": 500, "msg": str(e)}), 200
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=909, debug=False)
|
||||
@@ -0,0 +1,55 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import pymysql
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def get_db():
|
||||
return pymysql.connect(
|
||||
host="127.0.0.1",
|
||||
user="root",
|
||||
password="hp93000",
|
||||
database="alert_mail_stat",
|
||||
charset="utf8mb4"
|
||||
)
|
||||
|
||||
@app.route("/alert", methods=["POST"])
|
||||
def alert_receive():
|
||||
try:
|
||||
data = request.get_json()
|
||||
alerts = data.get("alerts", [])
|
||||
insert_num = 0
|
||||
update_num = 0
|
||||
db = get_db()
|
||||
cur = db.cursor()
|
||||
|
||||
for alert in alerts:
|
||||
fp = alert["fingerprint"]
|
||||
alert_name = alert["labels"].get("alertname", "")
|
||||
instance = alert["labels"].get("instance", "")
|
||||
severity = alert["labels"].get("severity", "warning")
|
||||
status = alert["status"]
|
||||
start_at = alert.get("startsAt", "")
|
||||
end_at = alert.get("endsAt")
|
||||
alert_type = 2 if status == "resolved" else 1
|
||||
content_str = str(alert)
|
||||
|
||||
sql = """
|
||||
INSERT INTO alert_log(mail_uid,alert_type,alert_name,instance,severity,starts_at,ends_at,content,receive_time)
|
||||
VALUES(%s,%s,%s,%s,%s,%s,%s,%s,NOW())
|
||||
"""
|
||||
cur.execute(sql, (fp, alert_type, alert_name, instance, severity, start_at, end_at, content_str))
|
||||
insert_num += 1
|
||||
|
||||
db.commit()
|
||||
cur.close()
|
||||
db.close()
|
||||
return jsonify({"code": 200, "insert": insert_num, "update": update_num})
|
||||
|
||||
except Exception as e:
|
||||
if "db" in locals():
|
||||
db.rollback()
|
||||
db.close()
|
||||
return jsonify({"code": 500, "msg": str(e)}), 200
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=909, debug=False)
|
||||
@@ -2,7 +2,6 @@
|
||||
session_start();
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Pragma: no-cache");
|
||||
require_once 'auth.php';
|
||||
$expire = 1800;
|
||||
if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time'] > $expire)) {
|
||||
session_destroy();
|
||||
@@ -81,7 +80,6 @@ td{padding:12px 10px;border-bottom:1px solid #F2F3F5;color:#1D2129;}
|
||||
<div class="nav-right">
|
||||
<a href="alert_subscribe.php" class="btn btn-outline"><i class="fa fa-bell"></i> 告警订阅管理</a>
|
||||
<span style="color:#4E5969;"><i class="fa fa-user"></i> <?php echo $userName; ?></span>
|
||||
<span class="user-info"><i class="fa fa-user-circle"></i><?php echo $t['current_user']; ?><?php echo $userName; ?>(<?php echo $roleRealName; ?>)</span>
|
||||
<button class="btn btn-danger" id="logoutBtn"><i class="fa fa-sign-out"></i> 退出登录</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,58 +25,28 @@ function getDbConn() {
|
||||
|
||||
// CSV导出接口(支持指定历史日期下载,不输出JSON头)
|
||||
if ($act === "export_csv") {
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$conn = getDbConn();
|
||||
mysqli_query($conn, "SET time_zone = '+08:00'");
|
||||
if (!$conn) {
|
||||
header("Content-Type:text/html;charset=utf-8");
|
||||
echo "数据库连接失败:" . mysqli_connect_error();
|
||||
exit;
|
||||
}
|
||||
|
||||
$singleDate = $_GET['date'] ?? '';
|
||||
$startDate = $_GET['start'] ?? '';
|
||||
$endDate = $_GET['end'] ?? '';
|
||||
$where = "";
|
||||
$fileName = "";
|
||||
|
||||
if (!empty($startDate) && !empty($endDate)) {
|
||||
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $endDate)) {
|
||||
// 接收自定义日期参数,不传则取今日
|
||||
$targetDate = $_GET['date'] ?? date("Y-m-d");
|
||||
// 简单日期格式校验 Y-m-d
|
||||
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $targetDate)) {
|
||||
header("Content-Type:application/json;charset=utf-8");
|
||||
echo json_encode(["code"=>400,"msg"=>"日期格式错误"], JSON_UNESCAPED_UNICODE);
|
||||
echo json_encode(["code"=>400,"msg"=>"日期格式错误,请使用 Y-m-d,例如 2026-07-01"], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
if ($startDate > $endDate) {
|
||||
header("Content-Type:application/json;charset=utf-8");
|
||||
echo json_encode(["code"=>400,"msg"=>"开始日期不能大于结束日期"], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
$where = "receive_time >= '$startDate 00:00:00' AND receive_time <= '$endDate 23:59:59'";
|
||||
$fileName = "告警报表_{$startDate}_至_{$endDate}.csv";
|
||||
} elseif (!empty($singleDate)) {
|
||||
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $singleDate)) {
|
||||
header("Content-Type:application/json;charset=utf-8");
|
||||
echo json_encode(["code"=>400,"msg"=>"日期格式错误"], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
$where = "DATE(receive_time) = '$singleDate'";
|
||||
$fileName = "告警报表_{$singleDate}.csv";
|
||||
} else {
|
||||
$today = date("Y-m-d");
|
||||
$where = "DATE(receive_time) = '$today'";
|
||||
$fileName = "告警报表_今日_{$today}.csv";
|
||||
}
|
||||
|
||||
// 调试:打印where条件,访问接口先看这个
|
||||
// echo "WHERE条件:".$where;exit;
|
||||
|
||||
$sql = "SELECT alert_type,alert_name,instance,severity,starts_at,receive_time
|
||||
FROM alert_log WHERE {$where} ORDER BY receive_time DESC";
|
||||
FROM alert_log WHERE DATE(receive_time) = '$targetDate' ORDER BY receive_time DESC";
|
||||
$res = mysqli_query($conn, $sql);
|
||||
|
||||
ob_clean();
|
||||
header("Content-Type: text/csv; charset=utf-8");
|
||||
header("Content-Disposition: attachment; filename={$fileName}");
|
||||
header("Content-Disposition: attachment; filename=告警报表_" . $targetDate . ".csv");
|
||||
echo "\xEF\xBB\xBF";
|
||||
$header = ["告警状态", "告警名称", "实例", "级别", "故障开始时间", "接收时间"];
|
||||
echo implode(",", $header) . "\r\n";
|
||||
@@ -99,6 +69,7 @@ if ($act === "export_csv") {
|
||||
mysqli_close($conn);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 所有JSON接口统一返回头
|
||||
header("Content-Type:application/json;charset=utf-8");
|
||||
$conn = getDbConn();
|
||||
@@ -322,25 +322,13 @@ button.normal:hover{
|
||||
|
||||
<!-- 9 导出CSV报表(带日历选择) -->
|
||||
<div class="card">
|
||||
<h3><i class="fa fa-download"></i>9. 导出告警CSV报表</h3>
|
||||
|
||||
<!-- 第一组:单日导出(原有功能保留) -->
|
||||
<div class="row" style="margin-bottom:12px;gap:10px;align-items:center;flex-wrap:wrap;">
|
||||
<label>单日导出:</label>
|
||||
<h3><i class="fa fa-download"></i>9. 导出告警CSV报表(支持历史日期)</h3>
|
||||
<div class="row">
|
||||
<label>选择日期:</label>
|
||||
<input type="date" id="csv_date" placeholder="留空导出今日">
|
||||
<button class="btn-success" onclick="exportCsvSingle()"><i class="fa fa-download"></i>下载单日报表</button>
|
||||
<button class="btn-success" onclick="exportCsv()"><i class="fa fa-download"></i>下载对应日期报表</button>
|
||||
</div>
|
||||
<div class="tip" style="margin-bottom:16px;">不选择日期默认导出今日告警;选择历史日期下载单日报表</div>
|
||||
|
||||
<!-- 第二组:区间导出(新增) -->
|
||||
<div class="row" style="gap:10px;align-items:center;flex-wrap:wrap;">
|
||||
<label>区间导出:</label>
|
||||
<input type="date" id="csv_start">
|
||||
<span>~</span>
|
||||
<input type="date" id="csv_end">
|
||||
<button class="btn-primary" onclick="exportCsvRange()"><i class="fa fa-download"></i>下载区间报表</button>
|
||||
</div>
|
||||
<div class="tip">填写开始、结束日期,导出该时间段全部告警数据</div>
|
||||
<div class="tip">不选择日期默认导出今日告警;选择历史日期可下载过往报表</div>
|
||||
</div>
|
||||
|
||||
<!-- 返回结果输出 -->
|
||||
@@ -409,8 +397,8 @@ function simpleReq(act){
|
||||
})
|
||||
}
|
||||
|
||||
// 单日导出
|
||||
function exportCsvSingle(){
|
||||
// 导出CSV 支持日历选择日期
|
||||
function exportCsv(){
|
||||
const dateVal = document.getElementById("csv_date").value.trim();
|
||||
let url = `${apiUrl}?act=export_csv`;
|
||||
if(dateVal){
|
||||
@@ -418,23 +406,6 @@ function exportCsvSingle(){
|
||||
}
|
||||
window.open(url,"_blank");
|
||||
}
|
||||
|
||||
// 区间导出
|
||||
function exportCsvRange(){
|
||||
const startDate = document.getElementById("csv_start").value.trim();
|
||||
const endDate = document.getElementById("csv_end").value.trim();
|
||||
if(!startDate || !endDate){
|
||||
alert("请同时选择开始日期和结束日期");
|
||||
return;
|
||||
}
|
||||
if(startDate > endDate){
|
||||
alert("开始日期不能晚于结束日期");
|
||||
return;
|
||||
}
|
||||
let url = `${apiUrl}?act=export_csv`;
|
||||
url += `&start=${encodeURIComponent(startDate)}&end=${encodeURIComponent(endDate)}`;
|
||||
window.open(url,"_blank");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,7 +9,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
}
|
||||
session_start();
|
||||
$expire = 1800;
|
||||
if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time']) > $expire) {
|
||||
if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time'] > $expire)) {
|
||||
echo json_encode(['code' => 401, 'msg' => '登录失效']);
|
||||
exit;
|
||||
}
|
||||
@@ -42,8 +42,7 @@ mysqli_set_charset($connConf, "utf8mb4");
|
||||
// 获取当前用户角色权限
|
||||
$isAdmin = 0;
|
||||
$permList = "";
|
||||
$roleId = 0;
|
||||
$roleSql = "SELECT r.is_admin, r.perm_list, u.role_id FROM sys_user u LEFT JOIN sys_role r ON u.role_id=r.id WHERE u.uid = ?";
|
||||
$roleSql = "SELECT r.is_admin, r.perm_list FROM sys_user u LEFT JOIN sys_role r ON u.role_id=r.id WHERE u.uid = ?";
|
||||
$stmtRole = mysqli_prepare($connWork, $roleSql);
|
||||
mysqli_stmt_bind_param($stmtRole, 's', $loginUid);
|
||||
mysqli_stmt_execute($stmtRole);
|
||||
@@ -52,98 +51,12 @@ $roleRow = $roleRes ? mysqli_fetch_assoc($roleRes) : [];
|
||||
if ($roleRow) {
|
||||
$isAdmin = intval($roleRow['is_admin']);
|
||||
$permList = $roleRow['perm_list'];
|
||||
$roleId = intval($roleRow['role_id'] ?? 0);
|
||||
}
|
||||
|
||||
// 读取当前角色页面权限列表(用于分发工单权限判断)
|
||||
$allowPages = [];
|
||||
if ($roleId > 0) {
|
||||
$permSql = "SELECT page_key FROM sys_role_permission WHERE role_id = ?";
|
||||
$stmtPerm = mysqli_prepare($connWork, $permSql);
|
||||
mysqli_stmt_bind_param($stmtPerm, 'i', $roleId);
|
||||
mysqli_stmt_execute($stmtPerm);
|
||||
$pRes = mysqli_stmt_get_result($stmtPerm);
|
||||
while ($p = mysqli_fetch_assoc($pRes)) {
|
||||
$allowPages[] = $p['page_key'];
|
||||
}
|
||||
}
|
||||
|
||||
$action = $_REQUEST['action'] ?? '';
|
||||
$post = json_decode(file_get_contents("php://input"), true) ?: [];
|
||||
|
||||
// ===================== 工单列表查询(新增,解决数据可见权限隔离) =====================
|
||||
if ($action === "get_list") {
|
||||
$page = intval($_GET['page'] ?? 1);
|
||||
$size = intval($_GET['size'] ?? 20);
|
||||
$offset = ($page - 1) * $size;
|
||||
$status = trim($_GET['status'] ?? '');
|
||||
$keyword = trim($_GET['keyword'] ?? '');
|
||||
|
||||
$where = [];
|
||||
$param = [];
|
||||
$paramType = '';
|
||||
|
||||
// 普通用户:仅能查看自己创建 或 分配给自己的工单;管理员无限制查看全部
|
||||
if ($isAdmin !== 1) {
|
||||
$where[] = "(create_uid = ? OR assign_uid = ?)";
|
||||
$param[] = $loginUid;
|
||||
$param[] = $loginUid;
|
||||
$paramType .= 'ss';
|
||||
}
|
||||
|
||||
if ($status !== '') {
|
||||
$where[] = "status = ?";
|
||||
$param[] = $status;
|
||||
$paramType .= 'i';
|
||||
}
|
||||
if ($keyword !== '') {
|
||||
$where[] = "(title LIKE ? OR content LIKE ?)";
|
||||
$param[] = "%$keyword%";
|
||||
$param[] = "%$keyword%";
|
||||
$paramType .= 'ss';
|
||||
}
|
||||
|
||||
$whereSql = $where ? "WHERE " . implode(" AND ", $where) : "";
|
||||
|
||||
// 分页列表
|
||||
$listSql = "SELECT * FROM work_order $whereSql ORDER BY create_time DESC LIMIT ?,?";
|
||||
$param[] = $offset;
|
||||
$param[] = $size;
|
||||
$paramType .= 'ii';
|
||||
|
||||
$stmtList = mysqli_prepare($connWork, $listSql);
|
||||
mysqli_stmt_bind_param($stmtList, $paramType, ...$param);
|
||||
mysqli_stmt_execute($stmtList);
|
||||
$res = mysqli_stmt_get_result($stmtList);
|
||||
$list = [];
|
||||
while ($row = mysqli_fetch_assoc($res)) {
|
||||
$list[] = $row;
|
||||
}
|
||||
|
||||
// 总数统计
|
||||
$countSql = "SELECT COUNT(id) total FROM work_order $whereSql";
|
||||
$stmtCount = mysqli_prepare($connWork, $countSql);
|
||||
array_pop($param);
|
||||
array_pop($param);
|
||||
$paramTypeCount = rtrim($paramType, 'ii');
|
||||
if ($paramTypeCount) {
|
||||
mysqli_stmt_bind_param($stmtCount, $paramTypeCount, ...$param);
|
||||
}
|
||||
mysqli_stmt_execute($stmtCount);
|
||||
$countRow = mysqli_fetch_assoc(mysqli_stmt_get_result($stmtCount));
|
||||
$total = intval($countRow['total']);
|
||||
|
||||
echo json_encode([
|
||||
'code' => 0,
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'size' => $size
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ===================== 根据告警ID查询关联工单 =====================
|
||||
// ===================== 新增1:根据告警ID查询关联工单 =====================
|
||||
if ($action === "get_workorder_by_alertid") {
|
||||
$alertId = trim($_GET['alert_id'] ?? '');
|
||||
if (empty($alertId)) {
|
||||
@@ -164,7 +77,7 @@ if ($action === "get_workorder_by_alertid") {
|
||||
exit;
|
||||
}
|
||||
|
||||
// ===================== 自动同步告警状态,批量更新工单为已完成 =====================
|
||||
// ===================== 新增2:自动同步告警状态,批量更新工单为已完成 =====================
|
||||
if ($action === "auto_sync_workorder_status") {
|
||||
// 1. 查询所有已恢复的告警(alert_type=2),去重获取告警ID
|
||||
$resolveSql = "SELECT DISTINCT CONCAT(alert_name,'_',instance) as alert_id FROM alert_log WHERE alert_type=2";
|
||||
@@ -315,11 +228,10 @@ if ($action === "update_status") {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 5、管理员/拥有system_manage权限角色 分发工单
|
||||
// 5、管理员分发工单(前端统一action=assign,废弃assign_order)
|
||||
if ($action === "assign") {
|
||||
// 修复:超级管理员 或 拥有system_manage页面权限均可分发工单
|
||||
if ($isAdmin !== 1 && !in_array("system_manage", $allowPages)) {
|
||||
echo json_encode(['code' => 403, 'msg' => '无工单分发权限,请联系管理员']);
|
||||
if ($isAdmin !== 1) {
|
||||
echo json_encode(['code' => 403, 'msg' => '仅管理员可分发工单']);
|
||||
exit;
|
||||
}
|
||||
$id = intval($post['id'] ?? 0);
|
||||
@@ -355,7 +267,7 @@ if ($action === 'save_lang') {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 同步Prometheus实时告警,自动清理恢复告警
|
||||
// 新增:同步Prometheus实时告警,自动清理恢复告警(完全独立,无需index.php)
|
||||
if ($action === "sync_prom_alerts") {
|
||||
$promUrl = "http://10.150.117.190:9090/api/v1/alerts";
|
||||
$resp = @file_get_contents($promUrl);
|
||||
@@ -26,7 +26,7 @@ $userName = htmlspecialchars($_SESSION['username'] ?? '');
|
||||
$isAdmin = intval($_SESSION['is_admin'] ?? 0);
|
||||
$userRoleId = intval($_SESSION['role_id'] ?? 0);
|
||||
|
||||
// ====================== 双库固定连接 ======================
|
||||
// ====================== 双库固定连接(修复null根源) ======================
|
||||
$dbHost = "10.150.117.190";
|
||||
$dbUser = "root";
|
||||
$dbPass = "hp93000";
|
||||
@@ -48,43 +48,27 @@ if (!$connMonitor) {
|
||||
mysqli_set_charset($connMonitor, "utf8mb4");
|
||||
// ========================================================================
|
||||
|
||||
// ========== 新增:读取角色真实名称 ==========
|
||||
$roleRealName = "未知角色";
|
||||
if ($userRoleId > 0) {
|
||||
$getRoleSql = "SELECT role_name FROM sys_role WHERE id = $userRoleId";
|
||||
$roleResult = mysqli_query($connMonitor, $getRoleSql);
|
||||
if ($roleResult && $roleRow = mysqli_fetch_assoc($roleResult)) {
|
||||
$roleRealName = $roleRow['role_name'];
|
||||
}
|
||||
}
|
||||
// 超级管理员强制覆盖文字
|
||||
if ($isAdmin === 1) {
|
||||
$roleRealName = "超级管理员";
|
||||
}
|
||||
// ===========================================
|
||||
// 获取当前访问页面文件名(去掉.php后缀)
|
||||
$currentPage = basename($_SERVER['SCRIPT_NAME'], '.php');
|
||||
|
||||
// 1. 登录时一次性加载当前角色全部权限,存入全局变量(侧边栏共用)
|
||||
$allowPages = [];
|
||||
if ($userRoleId > 0) {
|
||||
// 非超级管理员校验页面权限
|
||||
if ($isAdmin !== 1) {
|
||||
$permSql = "SELECT page_key FROM sys_role_permission WHERE role_id = $userRoleId";
|
||||
$permRes = mysqli_query($connMonitor, $permSql);
|
||||
$allowPages = [];
|
||||
if ($permRes) {
|
||||
while ($row = mysqli_fetch_assoc($permRes)) {
|
||||
$allowPages[] = $row['page_key'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 获取当前访问页面文件名(去掉.php后缀)
|
||||
$currentPage = basename($_SERVER['SCRIPT_NAME'], '.php');
|
||||
|
||||
// 3. 非管理员自动拦截无权限页面(全局统一校验,无需每个页面重复写)
|
||||
if ($isAdmin !== 1 && !in_array($currentPage, $allowPages)) {
|
||||
// 无权限拦截
|
||||
if (!in_array($currentPage, $allowPages)) {
|
||||
echo "<script>alert('无访问权限!');history.back();</script>";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// 读取右上角未读消息数量
|
||||
// 读取右上角未读消息数量(修复第79/84/86行报错)
|
||||
$unreadMsgCount = 0;
|
||||
$msgSql = "SELECT COUNT(id) cnt FROM sys_user_msg WHERE user_id = $loginUserId AND is_read = 0";
|
||||
$msgRes = mysqli_query($connMonitor, $msgSql);
|
||||
@@ -158,6 +142,4 @@ if (!empty($sidebarRawLinks)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 【已删除冲突无用函数 hasPagePerm】
|
||||
?>
|
||||
@@ -6,14 +6,6 @@ header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Pragma: no-cache");
|
||||
header("Expires: Thu, 01 Jan 1970 00:00:00 GMT");
|
||||
|
||||
|
||||
require_once 'auth.php';
|
||||
// 权限拦截
|
||||
if (!hasPagePerm('dashboard')) {
|
||||
echo "<script>alert('无访问权限');location.href='login.php';</script>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// 会话超时:30分钟无操作自动登出,与admin后台统一
|
||||
$expire = 1800;
|
||||
if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time'] > $expire)) {
|
||||
@@ -59,7 +51,6 @@ $langMap = [
|
||||
'monitor_panel' => '监控面板',
|
||||
'alert_overview' => '告警监控总览',
|
||||
'disk_capacity' => '服务器磁盘容量',
|
||||
'docker_mgr' => 'Docker容器管理',
|
||||
'alert_list_page' => '历史告警查询',
|
||||
'work_order_mgr' => '工单系统',
|
||||
'system_manager' => '角色管理',
|
||||
@@ -133,7 +124,6 @@ $langMap = [
|
||||
'monitor_panel' => 'Monitor Panel',
|
||||
'alert_overview' => 'Alert Overview',
|
||||
'disk_capacity' => 'Server Disk Capacity',
|
||||
'docker_mgr' => 'Docker Manager',
|
||||
'alert_list_page' => 'Alert Pagination List',
|
||||
'work_order_mgr' => 'Work Order System',
|
||||
'system_manager' => 'Role & Permission Manage',
|
||||
@@ -654,10 +644,6 @@ tbody tr:nth-child(even){background:#fbfcfe}
|
||||
<i class="fa fa-hdd-o"></i>
|
||||
<span><?php echo $t['disk_capacity']; ?></span>
|
||||
</div>
|
||||
<div class="menu-item" onclick="location.href='docker_mgr.php'">
|
||||
<i class="fa fa-cubes"></i>
|
||||
<span><?php echo $t['docker_mgr']; ?></span>
|
||||
</div>
|
||||
<!-- 告警分页:去掉window.open,同页跳转 -->
|
||||
<div class="menu-item" onclick="location.href='alert_list.php'">
|
||||
<i class="fa fa-list"></i>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user