From 6cfde5dcb42f23e4d01859d46145ec81ef541c07 Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Tue, 28 Oct 2025 16:19:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=9B=B4=E6=96=B0=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E5=92=8C=E6=9F=A5=E8=AF=A2=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- apis/__pycache__/log.cpython-310.pyc | Bin 962 -> 1254 bytes apis/log.py | 11 ++- config/__pycache__/database.cpython-310.pyc | Bin 859 -> 792 bytes config/database.py | 1 - config/logging.py | 32 +++++++ models/__pycache__/log_alert.cpython-310.pyc | Bin 896 -> 942 bytes models/log_alert.py | 11 +-- requirements.txt | 2 +- schemas/__pycache__/log_alert.cpython-310.pyc | Bin 795 -> 1473 bytes schemas/log_alert.py | 17 ++++ .../log_alert_service.cpython-310.pyc | Bin 2170 -> 3209 bytes .../message_service.cpython-310.pyc | Bin 1092 -> 1110 bytes service/log_alert_service.py | 82 ++++++++++++------ service/message_service.py | 3 +- utils/__pycache__/time.cpython-310.pyc | Bin 899 -> 864 bytes utils/time.py | 4 +- 17 files changed, 128 insertions(+), 38 deletions(-) create mode 100644 config/logging.py diff --git a/.gitignore b/.gitignore index 7ddac70..3a2e874 100644 --- a/.gitignore +++ b/.gitignore @@ -65,4 +65,5 @@ media/ .DS_Store logs/ -packages/ \ No newline at end of file +packages/ +*.db \ No newline at end of file diff --git a/apis/__pycache__/log.cpython-310.pyc b/apis/__pycache__/log.cpython-310.pyc index 656dd7c097bf2e612635bc21fb85de5cd150e08f..c05b3b136d6445aac0022f67d2a9cd7a04117d6a 100644 GIT binary patch literal 1254 zcmZ`(OKTKC5bo}ooqf%|lBkIN4;6YFj z#UO$ph~NWMJg6t}=>O=eBt);?1i`AAP1p!FbZ=Gl*H!gZ)ofC$RS2vvH%a)_BIG+N zldA;E8QAJ49Gq|(k(hdvqRb)|Tb>o$o}KAdREQnV$z(e!#wD+m$%UvKSG-DG^{Scf zL~dO3YLp0z7kMe5yv!@S8q$z*cir;pqJE>nYrM`I>rB|9beHxiZwjZ+c#BWnE8L}C zGs8^t89_yLj_^I})(Xk}=d@0&nRfydch9_K^_aeTj+?mPSdKbU!*;fIz;`|uCo zOWM@fmqVr7%#_bwxpXy2wUDNGUJS*6E4VE#38lhh0HPBJ-Qit;HZCW@*+@uzO@=`L z51QMCt3nNvff4|3MM=={5!F#b-U@qSt+D{N<9-A&QWv6cK6|_I?b*hYhg%=tg-GuoX^;Ca>si@|rG@4|K83WEpIxx{?Yx%9*sOY=Z3r zk<;+=`^5Q^%jZ^CmoJ3+V%ohTlN+L^)pAY}h#wylU-pM#W}Y98vTsQbOm>N0g@5TXy(TZ+Aw##{DmQ0mZHA({@upoCzF|)a^89zB}WRK%E5p0 zll#EMuAFK*AF6T1nVdremi?b>Olupt6Yc<_a2zB`i|swe(W7BF2qY$KihW;c=!L|t zODvIBS1XYp^{$I}G@r;=77*9yC4+t#%yVD+T_2k0Ahe|r=BxQU9Q0Qf(GUKEc*Sw6 z^Olzou8_A&Yw!mLrB delta 577 zcmY+9&uY|A6vpp4lO{8nBr};mT47e=CYwT+LMfE43L;{4VL&AI-bo_~w>`;N3WZs; z+b&8Tz&{|RAh_@ie2hFm(Y-DO&rKEe!abbt@Z&q*x$b>&0`2>*;P>?NkNr!$2xfOa zvXVkVE((aDz!<@3%rCa1B?tx5mQD(?D|^z-AOqPy@5Fu8f8|L}`Z732g~~pKImm&s z<|v0UJX<-1*k>kSX7nF3R$ar%i5kppIhD6sb|`P}ifHwl$rfSL+j_L~STE{zxI2Po z@Ia?qxuWU`WofFYK7zs>F?s#w!`Dym>+i5Lb67V0!-b;b7l~mbpnzvrg2MV4-k%Iv z4EUGG#YHl@e%{$$mL7MNcnc@u1m5AUAcI9n#xnM+o1MQ+k;Xi2ohdY3TTGTF{6pqC zWx7%{;c>gpLz;5`FbW%Io|IK`kdcW&9U;ad4$8wk$@lhEalEFfAgf-trppxu;;=O1 zq+Gi(<-5o>bEj1FI@?oi$i^nU;C)ReRaJXfV;$(SYOI%9=k4l$!v0O%-6*tNJ!cg>>mK|9tfYr2 diff --git a/apis/log.py b/apis/log.py index 7acd199..3784d7a 100644 --- a/apis/log.py +++ b/apis/log.py @@ -1,8 +1,10 @@ +from typing import List + from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from config.database import get_db -from schemas.log_alert import LogAlertTrigger +from schemas.log_alert import LogAlertTrigger, LogAlertResponse from service import log_alert_service router = APIRouter( @@ -12,11 +14,16 @@ router = APIRouter( ) -@router.get("", summary="查询日志告警") +@router.get("", summary="查询所有日志告警") def query_alert(db: Session = Depends(get_db)): return log_alert_service.query_alert(db) +@router.get("/name", summary="查询指定日志告警", response_model=List[LogAlertResponse]) +def query_alert(name: str, db: Session = Depends(get_db)): + return log_alert_service.query_alert_by_name(name, db) + + @router.post("", summary="触发日志告警") def trigger_log_alter(log_alter: LogAlertTrigger, db: Session = Depends(get_db)) -> bool: return log_alert_service.trigger_alert(log_alter, db) diff --git a/config/__pycache__/database.cpython-310.pyc b/config/__pycache__/database.cpython-310.pyc index 0c1b3f54f80e6ce8feda9f5ff915848116179174..5a84fe958aa3bc0b66b790291987ebb3b92743d8 100644 GIT binary patch delta 420 zcmYL^zfQw25XNJtF-fq~3J?-Q2R0(44j{pT7!eaow=9(#A0bu#2*(|mU|{VKb%BkQ zhv5axJMao{E=YLz&i?sy_kEx2g^5;(*mGy zQw$;%uKX-kk&2(aY+G$Bj+HAh_0pt&JLo^o$Cl@9(?D)!QWst7+gL75o40jc8oNFu zS0@qfO9wi@V#6AYRMJQr=NhDenXD?ypef1*-aRd_NsIL>xfVmbb`)iY=;8W{EFOP9 zT}OgqSpjCI=DV)XrJ_%aQWBDVsvWyYg^j!WN>=$D)DPN?vdKS~w7S+l!YsiAw`DQu zz?iZr^uWPU-72WMN!1qU5wy|LCBXFPel9zhEp??iB0X~A>~8k{WpK}p;f>eu0>>>Y YxFpECJrwS7!YL<|#)N$*LFn_r4?S~bHUIzs delta 508 zcmYjNy-ve05RTn8NfWyuggPKGqY9}5tcVeqSlGNoCU=BDe&FmPm|$S-P<3HtCG1%v4zYDwZ#mZqHNF+%Yb>M zN!#)Yvtw;MCkz@>woR?ik=%Rsys@rC-Zl;9Hq%s?QAZ_uV%xl}>(Z(@V|!bX@6e^t znMGWq)u63b$xlOFRg3Vu>r+5pBPH`2b|9CXYq*0IMq>WL&ThYhJ|lIo2n)0s9IyI3 zAL4f*=PYJJPX6!VXh|jJveH$4iuDcoQflpw7~{1a{}V|apD_5B&{9p^FVaaoDbr$X z(Au&os5gJ)!`v%!dv$93ezFNw)OQp~55j|=<44o4_ceRGQ@1dwaF;pW3>}C-Fn76N OoF^>&81&+f=zanU&wuIw diff --git a/config/database.py b/config/database.py index 3440129..ce92b19 100644 --- a/config/database.py +++ b/config/database.py @@ -1,5 +1,4 @@ from sqlalchemy import create_engine -from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from config.setting import settings diff --git a/config/logging.py b/config/logging.py new file mode 100644 index 0000000..eee43be --- /dev/null +++ b/config/logging.py @@ -0,0 +1,32 @@ +import sys + +from loguru import logger + +from config.setting import settings + +# 日志级别 +LOG_LEVEL = settings.log_level.upper() + +# 日志格式 +STDOUT_FORMAT = ( + "{time:YYYY-MM-DD HH:mm:ss.SSS} | " + "{level: <8} | " + "{name}:{function}:{line} - " + "{message}" +) + +# 移除默认处理器 +logger.remove() + +# 添加控制台处理器 +logger.add( + sink=sys.stdout, + level=LOG_LEVEL, + format=STDOUT_FORMAT, + colorize=True, + backtrace=True, # 显示完整异常堆栈 + diagnose=True, # 显示详细异常信息 +) + +# 导出配置好的logger +__all__ = ["logger"] diff --git a/models/__pycache__/log_alert.cpython-310.pyc b/models/__pycache__/log_alert.cpython-310.pyc index a77da786a92ea1492acf148ce5168edc889c4588..119b1b87e1fd7d008d0648d280bd38af48fca1da 100644 GIT binary patch delta 372 zcmYk0y-ve05P)MR#Lh3FRH$qqflwr#fDMVMLJY8ZDK0iqkeft~GlP`5MU|g|h4&$E z(6_)zkcx-%cX!|E?gM?JxQrs-GVe=Td1!Cr4s5o&%XbFZ!5R|G9q#?H|BnO1h&e52 z0SOI9=8uP(+X99dHnWGL&y%+!=B;fq+2=#eUpwTO1y5EQcKE)`ZUvW$_@c}fR5##! zo`Mb+jSzGx_-<-$>`=uEmKT}nAjV&5BUB1yWLh#YA+`71;j(BdMiqZZr}_sx-brK> z;!~lxT&R4-3GR0dB%td~#wCTMmd} b0zweN5a=De0YqQe*U9J&avx6hvwijp&Z=G= delta 286 zcmZ3--oVb6&&$ij00ftoea+a;G?DKXW7)))s$tEHQ5>l(sjNVn6H0RdX>K5&2S~H0 z0A*6xQrLT$qIiLPz7(cZ{w#qMj$Y;{K?ENx#@WjfC6vMy%%I6VxrWhb@-9YcjawXf zr8zl?Nja%S{6Nb!nTrH~6qtRBBR{XSASJOR)lXA+@(;!!^C#=r)Z&uF z+=5%2aApx3P~RO=2tZVUm4XPF$$iWU0O=V?D*ylh diff --git a/models/log_alert.py b/models/log_alert.py index 791d8ad..548da62 100644 --- a/models/log_alert.py +++ b/models/log_alert.py @@ -10,12 +10,13 @@ class LogAlert(Base): __tablename__ = "log_alerts" id = Column(Integer, primary_key=True, index=True) - alter_name = Column(String(50)) - alter_timestamp = Column(Integer) + alter_name = Column(String(50), nullable=True) + alter_time = Column(DateTime, nullable=True) - timestamp = Column(Integer) - message = Column(Text) - status = Column(String(20), default="pending") # pending, notified, resolved + log_time = Column(DateTime, nullable=True) + log_topic = Column(String(50)) + log_message = Column(Text) + log_status = Column(String(20), default="pending") # pending, notified, resolved create_time = Column(DateTime, nullable=True, default=datetime.now) update_time = Column(DateTime, nullable=True, default=datetime.now, onupdate=datetime.now) diff --git a/requirements.txt b/requirements.txt index ad92be6..01b4c0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -fastapi~=0.119.0 pydantic~=2.12.2 SQLAlchemy~=2.0.44 requests~=2.32.5 pydantic-settings~=2.11.0 uvicorn~=0.38.0 \ No newline at end of file +fastapi~=0.119.0 pydantic~=2.12.2 SQLAlchemy~=2.0.44 requests~=2.32.5 pydantic-settings~=2.11.0 uvicorn~=0.38.0 loguru~=0.7.3 \ No newline at end of file diff --git a/schemas/__pycache__/log_alert.cpython-310.pyc b/schemas/__pycache__/log_alert.cpython-310.pyc index 2c2bf8a96370d14b3af5e2627deda178133592ad..90e16153d242fd33659a34f2b2a5856d885a9c25 100644 GIT binary patch literal 1473 zcmZ`(&2AGh5cd8hn{7e@6e{tXOAbLwAE1h=LJ_S{8wxE4R+Uyx?1ZiMC$$~aMBLgd z?*K>Mhm)_I`U)HnGfvV*rE%ohne}8m{=UzfS1JL4@pw$)Up67XF<2Zf1Y0oW0T@P@ zm5`K##6sUrtke$e)CnDn>=5QK_ku8&+viT`LhP{u#03+35Eq#bv2Wr6D;<(%a0yjO z)6zbpimN!~O%S<+_BMN=4IQr&-W`WZp)R4x%W{*(l-Qm!s%( zL=()1$dO9uY825d%N12|o=JQgXX+;rcc39-{-l8Y~Kj~~n4XP#2C5}B3t;aGT3r+_C!6A<4jTjt$zDE1(6ITQvG2cSWS+}YEc zJqvAQZ^q8K9nQGXwK;GfxE#VUc~~;YbpVK&dj#l(ML3jke01_*+zSKn_PLaF0GZ$) z0#YNny!$5$-7_o1E^X#qkk|@6<^ql0WNmLoo?L6zpgQK1Wf1VHYQ6AecB})4% z`3|c6VL=VMGr8ON)M})y2CFxAHyZmJjYAY4Fxofbv$W0BHHo4M1+?EzXxe3Ta}8_4 zB>_Sv^(Eb`&yzt;!iQW@LW7;?YG34OM3oY8cci!!SW8zw)5hT-e-b$#hVd zp7cJXORVV=*YX|zuXqSSr&+wQkywG(qKpQ2Fj=?N6*XAJT!{{Nif z;9d$9Av47;+h-7;~ATm>3z{8B&;1m|GZ9 zm{S>>nWLD2e3leeAfFY?XGviTX3%7R2{LHn#AL>(iC?4Hcz~QDp2=a1PNFP8CI}a^ z0SPV!4n`ivB9_UrEKlk|0!8c~f&)Zwg9wm&ikLx!2#62^5#k_%6GT9ag|m1;EIuFs zk}L*Eg3RY&6am^HzzCM{(`3EHQBawZm{*dST*L&@05%=yB4dbNY=++Au*uC&Da}c> QV+5HDa;N}<0J8`y0GgaHKmY&$ diff --git a/schemas/log_alert.py b/schemas/log_alert.py index b626702..c03d0a0 100644 --- a/schemas/log_alert.py +++ b/schemas/log_alert.py @@ -1,3 +1,5 @@ +from datetime import datetime + from pydantic import BaseModel, Field @@ -6,6 +8,21 @@ class LogAlertTrigger(BaseModel): timestamp: int +class LogAlertResponse(BaseModel): + alterName: str + alterTime: datetime + logTime: datetime + logTopic: str + logMessage: str + logStatus: str + + class Config: + from_attributes = True + json_encoders = { + # 自定义 datetime 类型的序列化格式 + datetime: lambda dt: dt.strftime('%Y-%m-%d %H:%M:%S') + } + class OpenobserveQuery(BaseModel): start_time: int end_time: int diff --git a/service/__pycache__/log_alert_service.cpython-310.pyc b/service/__pycache__/log_alert_service.cpython-310.pyc index e6c1bb9334ecca2df98fd010af73f37262b71edf..dd5e30cfd8afb7a4300590b256f772235b284333 100644 GIT binary patch literal 3209 zcmcIm&2Jn@74NG4oKKHq$Bvy4%!dVIh(XJD2w{W0OQhWxw6;LBj7H<>nsIx(r=9AW z-8gDra3s)5fPw-mv5PXk>?#Lth|BI@($`ghaA74RR^+n$UiHk_3E@bO`pv6)Rj;bv z@AqDHQmd5>Jn!B%!uM*1@c}hXKOP#-<4yk#5f}lBjF|b1k>Vxuf$cqs@qOfi|c+}>uxj^H~dCC?N95r7oCY`{F!*xpVjSB zbT*#z=b)EGC8!8DsEYZn6V!tG9m_wbd#8HF#Nq{wU>cSMvUGWHCYV8Mk?d&A24~Sa zAIymhqZv$87Yz8D56;2ziC|&VXf8g&d5tE^t(U`8HO<@!`>BvBcTy3Fj>@g>px=Sr z-4tmWCVi;h%SrEAgh5T7PmT308TNWY=8bX3D`SXDdTZ^?EaV;bE=#+Wnd#~MzQ==DqZ zZ?z+Zt?*zcccf4Q+3#>V=I9};ZMU5}UlNqtWWOVb>?x4bXzXNsJGTJ zp^YC32oZ()(&r$Qp%`H0KR3E8U;)45Wo+FzVgT06_|OC`KpAM(u>lZGfM{)W2&C~t zJS^dz!JB>^qGx2rPv;NWFN{4nhvY|0v5W=A0vzL?Ef|n|0qz3pZRak($>G-a%O~{r zZI$eYo!lKKk&Ao_!hWym$a$I<27zCqGS^-pnd#v?F;DqKP*p zUeYG8nUAcG%XN=gTwDJOmPtwYJf`R(V4xUqfT2M_L9h;)GL^MQNy@2Y0|;|tK+O8^ z{=IukD=S5k{^jjoK78YNWd+GPpwKUsmp;7z+uxkn-~98VH~*yVV}vGgmK98pRS3Uy zitB8-GeclSK%Wi3ZLT*CW*dJ9GRj_OkBg8 z{tSZ1y$2EpptG`uHXVJ>Ii?=adeYhLQ-uEN|o`eZ&nEtH;yJKe@CVUs?{9maku4zHxbZ zb7bAp1qo!;3h{bN^Pl*8V|0%Y$2T>VpExz;9|66I_n*XToqsNX#T`KVD)LK*_5qg^ zpu8R@frwh*Vi>fQK=&8XEk8vXaju1>hz zj@mmSlC;O%OO@k8E7b`&9tsU+(R z$=#v?r%&xUubkTBI!5bC$$6Qb!LO`;{PC>EKdM*jT)sf7T6CE_aiSsP%MIbxPMVV3*~b|t?`;%g+R_{wjP_$G;OLHtjq z$jdZD!~AX1zB6e)34NFPDerE7?o?2Lj=p`LNr3662q3>pJ_vsKJPE2F&q7`}ulRv_^lzczUfT}mk_`m8kaNs)38_kQkqYn0Q z%Sa+SuKk-)JL>F;_@JoZM2UjO^%K)7zTBik;~P4w(pBVXksn3LpH9g|`*c5juN9f- zjxPP;6J~zYS{>EH@dv=E5?UUpFiKZ-4(V?ns;Nog|5h4*|M7 zbipjxZXyl!nNP)Uf_v^=!9fO*xJuW2N;g&2n8jB{6;-#&8u(S&oVj?uezxvhJo6th C857I^ literal 2170 zcmY*a&2Jk;6rY*>^x96GkETs4AY1@PY6Lw(6sQ_LBxpdS5@?mmT6-pr-CaAG8MjTf zKDiR85{Fhrm1t4z3sMhoLY%nqU(6L1krTZjp(0w|+l>=8&`=~ zfQ1@wQz+Hyc0lz%={C>D;0AqqtY4C?W>ZKo&2@K0r(1{pS49nFt05reoDv;gyCxbt zk*+0>ENTi+*Zd@sJ zPj(s%-{o*1C@#zkFx4Fpnxv#nIUTSq)@OZ7v!Ru;)EcqAo!Ud2vk~n(+DV-O<<=D@ z&v1K_q;%+NPx}KpENH(SV2&#gIikbji1gjm<)laDTNuk7@Rsfq?&>ne4d{LHz1{cp zl%8%^Qg6U0(K9JYoskIVyswn zj3=&(Mh^;TLx99W8Ry!Lkitx7b)6`-v)z(Pn;^G$qD06NZYrR_&Ik(^&wu{$`lnxP zoHM0*q#HZ6oIO=vmN94wgb4srnS*G2WC9)%p;N#*IfHph2rIAW$cE+ofrm_aMC8j5 z^K^av?X3&fuWx zkZK7;g_dYQOO{P-%cWD4J+m$LpYPc8lvM(|#Gve~4GXmKz#2L*(WcIU&_o0JL-rNf z2F7uA(@*I-831egz&YTZHG=B_GEuZivnXB#0e!9`-BVST zd(i>y$X4Do7LfB1&4EM&9P`_%Uk#>ps7+G)ae* z)wtV;Vzma!c=IJV50)*bpnElndqT+*_y`xWCoNsI^JgPNawgeICpu$;d<~6wAbA?Z z>o8RXgbygfS^lw~2W6kyEc3olUxe)FdiW9+DH#H2njuI-YeW#5KGjYJA3)b<2;t>< z1TeMQF4W#?dy8b~>jG%OfPyRn4sbb8vNxwoDdft5h4e2B1a}jrLWFa!Kp@?K>Z8lp zSf2a^vx*;=-CvEPq|T$YcX4}8k{d7W^@QBdsXSTZJQ9)~!CWn8rJZPcPXQv4RK|+p zID7grJ&YUeB5U$?KT2Zk>>FWcV1#bgK`IOyaRlFo?Uvxi$!rrZkWr>Mam;t{_=wa3 zbd^sl6i}kUGvATtz_?L8X^M?*j9(u3;;6hTf!d3sxUnOW{hTt0p_w|iuE1wPVjr4H z(&ZvnD@VPb(`!cI?r75PVYqjASLC-6c_`Tqewi6LzO diff --git a/service/__pycache__/message_service.cpython-310.pyc b/service/__pycache__/message_service.cpython-310.pyc index 4fabce2867068222fb7d9ed1534df6db042d5119..81956d0c7ab657acb4441236bb475e28db0eddaf 100644 GIT binary patch delta 137 zcmX@YagBpFpO=@50SK%@7&0$!%Qj3aju@xj1CFU02Vo6CXNxa2gl9`*DUs^Jmk$D}X!sHFivhqxfY`5fhMEBsuvHvofQ?WCa#80Ans0 A(f|Me diff --git a/service/log_alert_service.py b/service/log_alert_service.py index 1c91d37..50f492f 100644 --- a/service/log_alert_service.py +++ b/service/log_alert_service.py @@ -1,16 +1,19 @@ -from collections import defaultdict +from typing import List -from sqlalchemy import insert, select +from sqlalchemy import insert, select, func from sqlalchemy.orm import Session from models.log_alert import LogAlert -from schemas.log_alert import LogAlertTrigger +from schemas.log_alert import LogAlertTrigger, LogAlertResponse from service import openobserve_service from service.message_service import send_wechat_message, MessageEnum from utils.time import get_timestamp_range, format_timestamp +from config.logging import logger def trigger_alert(log_alter: LogAlertTrigger, db: Session) -> bool: + logger.info(f"{format_timestamp(log_alter.timestamp)} 发生告警:{log_alter.alter_name}") + start_time, end_time = get_timestamp_range(log_alter.timestamp, 60) result = openobserve_service.get_log(start_time, end_time) hits = result.get("hits") @@ -20,20 +23,19 @@ def trigger_alert(log_alter: LogAlertTrigger, db: Session) -> bool: return False # 判断日志告警是否已经存在 - log_db_alter = db.execute( - select(LogAlert) - .where(LogAlert.alter_timestamp == log_alter.timestamp) - ).first() + stmt = select(LogAlert).where(LogAlert.alter_time == format_timestamp(log_alter.timestamp)) + log_db_alter = db.execute(stmt).first() if log_db_alter is not None: return False - # 企业微信通知 - alter_message = f"🔔 **告警服务**:{log_alter.alter_name} \n 🕒 **告警时间**:{format_timestamp(log_alter.timestamp)}" - send_wechat_message(MessageEnum.MARKDOWN2, alter_message) - # 批量插入 - return batch_insert(log_alter, hits, db) + batch_insert(log_alter, hits, db) + + # 通知消息 + # notify_message(log_alter) + + return True def batch_insert(log_alter: LogAlertTrigger, hits: [], db: Session) -> bool: @@ -41,10 +43,11 @@ def batch_insert(log_alter: LogAlertTrigger, hits: [], db: Session) -> bool: [ { "alter_name": log_alter.alter_name, - "alter_timestamp": log_alter.timestamp, - "timestamp": hit["_timestamp"], - "message": hit["message"], - "status": "pending" + "alter_time": format_timestamp(log_alter.timestamp), + "log_time": format_timestamp(hit["_timestamp"]), + "log_topic": hit["topic"], + "log_message": hit["message"], + "log_status": "pending" } for hit in hits ] @@ -56,15 +59,44 @@ def batch_insert(log_alter: LogAlertTrigger, hits: [], db: Session) -> bool: return True +def notify_message(log_alter: LogAlertTrigger): + # 企业微信通知 + alter_message = f"🔔 **告警服务**:{log_alter.alter_name} \n 🕒 **告警时间**:{format_timestamp(log_alter.timestamp)}" + send_wechat_message(MessageEnum.MARKDOWN2, alter_message) + + def query_alert(db: Session): - alerts = db.execute(select(LogAlert)).scalars().all() + stmt = ( + select( + LogAlert.alter_name.label("alterName"), + func.strftime("%Y-%m-%d %H:%M:%S", LogAlert.alter_time).label("alterTime"), + func.strftime("%Y-%m-%d %H:%M:%S", LogAlert.log_time).label("logTime"), + LogAlert.log_topic.label("logTopic"), + LogAlert.log_message.label("logMessage"), + LogAlert.log_status.label("logStatus") + ) + .order_by(LogAlert.alter_name.desc(), LogAlert.alter_time.desc()) + ) - # 按照name和timestamp分类 - classified = defaultdict(lambda: defaultdict(list)) - for alert in alerts: - classified[alert.alter_name][alert.alter_timestamp].append({ - "timestamp": format_timestamp(alert.timestamp), - "message": alert.message - }) + results = db.execute(stmt).fetchall() - return dict(classified) + return [LogAlertResponse.model_validate(result) for result in results] + + +def query_alert_by_name(name: str, db: Session) -> List[LogAlertResponse]: + stmt = ( + select( + LogAlert.alter_name.label("alterName"), + func.strftime("%Y-%m-%d %H:%M:%S", LogAlert.alter_time).label("alterTime"), + func.strftime("%Y-%m-%d %H:%M:%S", LogAlert.log_time).label("logTime"), + LogAlert.log_topic.label("logTopic"), + LogAlert.log_message.label("logMessage"), + LogAlert.log_status.label("logStatus") + ) + .where(LogAlert.alter_name == name) + .order_by(LogAlert.alter_time.desc(), LogAlert.log_time.asc()) + ) + + results = db.execute(stmt).fetchall() + + return [LogAlertResponse.model_validate(result) for result in results] diff --git a/service/message_service.py b/service/message_service.py index c10d057..dd0772b 100644 --- a/service/message_service.py +++ b/service/message_service.py @@ -26,7 +26,8 @@ def send_wechat_message(message_type: MessageEnum, message: str): settings.wechat_webhook_url, headers={"Content-Type": "application/json"}, params={'key': settings.wechat_webhook_key}, - data=json.dumps(wechat_message, ensure_ascii=False).encode('utf-8') + data=json.dumps(wechat_message, ensure_ascii=False).encode('utf-8'), + timeout=5 ) return True diff --git a/utils/__pycache__/time.cpython-310.pyc b/utils/__pycache__/time.cpython-310.pyc index ef6824413006460e849bc98412061764fe35a44a..5d20f3616490f7ea31177931bbff32fadbde5e10 100644 GIT binary patch delta 95 zcmZo>f566@&&$ij00gaB44KO&@}@8{Y%Ee@GT;LWl`t$|tYJuDlxA4S7|fu_QVC_Xum*$4pY*A@W) delta 115 zcmaFB*38bE&&$ij00gCnzh>;8$eY5*vav{s$y5X=RKl=;v4$aqQJP^P;{v7>riF~b z44TY-MchESDnZpqUDaG&)f5F)4=Yt)E7f34=E)nFM7VBo6qgjGm1O3oPCmk9$Rfg6 QBr*9XlL@25WIbjh0A2hX=>Px# diff --git a/utils/time.py b/utils/time.py index 0aac705..9aabd55 100644 --- a/utils/time.py +++ b/utils/time.py @@ -21,5 +21,5 @@ def get_timestamp_range(ts: int, delta_seconds: int = 5, unit: str = "microsecon return ts - delta, ts + delta -def format_timestamp(timestamp: int) -> str: - return datetime.fromtimestamp(timestamp / 1_000_000).strftime("%Y-%m-%d %H:%M:%S") +def format_timestamp(timestamp: int) -> datetime: + return datetime.fromtimestamp(timestamp / 1_000_000)