From 0dd9d36e738fb543fb42edebe45c4c8efdb1f0a8 Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Mon, 20 Oct 2025 13:17:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=8F=92=E5=85=A5=E5=92=8C=E6=9F=A5=E8=AF=A2=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 11 ++ .idea/.gitignore | 8 + .idea/inspectionProfiles/Project_Default.xml | 12 ++ .../inspectionProfiles/profiles_settings.xml | 6 + .idea/log-alert-service.iml | 14 ++ .idea/misc.xml | 7 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + __pycache__/main.cpython-310.pyc | Bin 0 -> 468 bytes apis/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 407 bytes apis/__pycache__/log.cpython-310.pyc | Bin 0 -> 962 bytes apis/log.py | 13 +- config/__pycache__/database.cpython-310.pyc | Bin 0 -> 859 bytes config/__pycache__/setting.cpython-310.pyc | Bin 0 -> 765 bytes config/setting.py | 17 +- id_generator/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 166 -> 0 bytes .../__pycache__/generator.cpython-312.pyc | Bin 1533 -> 0 bytes .../__pycache__/options.cpython-312.pyc | Bin 1142 -> 0 bytes .../__pycache__/snowflake.cpython-312.pyc | Bin 735 -> 0 bytes .../__pycache__/snowflake_m1.cpython-312.pyc | Bin 6929 -> 0 bytes id_generator/generator.py | 38 ----- id_generator/idregister.py | 134 ---------------- id_generator/options.py | 43 ----- id_generator/snowflake.py | 20 --- id_generator/snowflake_m1.py | 147 ------------------ logs.db | Bin 12288 -> 53248 bytes models/__pycache__/base.cpython-312.pyc | Bin 2066 -> 0 bytes models/__pycache__/log_alert.cpython-310.pyc | Bin 0 -> 896 bytes models/base.py | 40 ----- models/log_alert.py | 16 +- requirements.txt | 2 +- schemas/__pycache__/log_alert.cpython-310.pyc | Bin 0 -> 795 bytes .../log_alert_service.cpython-310.pyc | Bin 0 -> 2170 bytes .../message_service.cpython-310.pyc | Bin 0 -> 1092 bytes .../openobserve_service.cpython-310.pyc | Bin 0 -> 769 bytes service/log_alert_service.py | 85 +++++++--- service/message_service.py | 32 ++++ service/openobserve_service.py | 20 +-- utils/__pycache__/time.cpython-310.pyc | Bin 0 -> 899 bytes utils/time.py | 25 +++ 41 files changed, 226 insertions(+), 478 deletions(-) create mode 100644 .env create mode 100644 .idea/.gitignore create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/log-alert-service.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 __pycache__/main.cpython-310.pyc create mode 100644 apis/__pycache__/__init__.cpython-310.pyc create mode 100644 apis/__pycache__/log.cpython-310.pyc create mode 100644 config/__pycache__/database.cpython-310.pyc create mode 100644 config/__pycache__/setting.cpython-310.pyc delete mode 100644 id_generator/__init__.py delete mode 100644 id_generator/__pycache__/__init__.cpython-312.pyc delete mode 100644 id_generator/__pycache__/generator.cpython-312.pyc delete mode 100644 id_generator/__pycache__/options.cpython-312.pyc delete mode 100644 id_generator/__pycache__/snowflake.cpython-312.pyc delete mode 100644 id_generator/__pycache__/snowflake_m1.cpython-312.pyc delete mode 100644 id_generator/generator.py delete mode 100644 id_generator/idregister.py delete mode 100644 id_generator/options.py delete mode 100644 id_generator/snowflake.py delete mode 100644 id_generator/snowflake_m1.py delete mode 100644 models/__pycache__/base.cpython-312.pyc create mode 100644 models/__pycache__/log_alert.cpython-310.pyc delete mode 100644 models/base.py create mode 100644 schemas/__pycache__/log_alert.cpython-310.pyc create mode 100644 service/__pycache__/log_alert_service.cpython-310.pyc create mode 100644 service/__pycache__/message_service.cpython-310.pyc create mode 100644 service/__pycache__/openobserve_service.cpython-310.pyc create mode 100644 service/message_service.py create mode 100644 utils/__pycache__/time.cpython-310.pyc create mode 100644 utils/time.py diff --git a/.env b/.env new file mode 100644 index 0000000..262d663 --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +log_level=DEBUG + +# sqlite连接方式:sqlite:/// +database_url=sqlite:///./logs.db + +wechat_webhook_url=https://qyapi.weixin.qq.com/cgi-bin/webhook/send +wechat_webhook_key=f09eb098-f709-4fc6-83b5-4a08a8431b8f + +openobserve_url=http://172.29.100.41:5080/api/default/_search +openobserve_username=developer@estun.com +openobserve_password=developer123 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..3dce9c6 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/log-alert-service.iml b/.idea/log-alert-service.iml new file mode 100644 index 0000000..b9dcfb8 --- /dev/null +++ b/.idea/log-alert-service.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d5b6360 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d88adc6 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/__pycache__/main.cpython-310.pyc b/__pycache__/main.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd24eb6b6f2fb917dc67ee7f274d0266ac268098 GIT binary patch literal 468 zcmYjNJ4*vW5Z=9aj*E|fkTykPFCvDBQ3xTBZaD~>+s(OhFLw7rw2f{4gO>SA*IL=w z*;qN72xeerzL{mdZ)VGOJ49fk?f2ss>^-(K zCwGa95y#A7?iLe|dv8AT-ZAr8@QOB=1l;D{#>}>6s2hF)BkJPDzoSYIrVjwmBu|CX zT+U@#LsC0<7KPArws<)omuY8^aj82qE>|MqFyU&UGv4@0Q>p7JF`UPSp%{WIbEZZc zWVQu$JdqA`c1Q-0_TlH^_A(x>*YQZ``+6~zp*V8-JPdDrb$KeW7pCAY#Xhmw8P)Y<7yka#^JnTJ5 zOD22~ym^T)!Uqx$cE~3&wc%~9&Gq7bNB`ykn$AeDJa5~=?f%2{9_AENM+mQEMGO^G zur0$s2&(eAb(%p7vQ(Rx*(0?ss!qtPR~=T(vhQOGKB{~Wa1OuEZqC!`W|Pj8x$7Pm z(5z%(bc*~*UP&+$E#X-eGR<41(=1bKWwPwFeX++NmrCQ!y|8w&nju6KMp))?V8aq^ n;!|*Y%TX4b88~p@NWWL?!J*>~F6u^fmArK3b$~D;BO37^UOQdw literal 0 HcmV?d00001 diff --git a/apis/__pycache__/log.cpython-310.pyc b/apis/__pycache__/log.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..656dd7c097bf2e612635bc21fb85de5cd150e08f GIT binary patch literal 962 zcmY*X&ui2`6rP#QCcD|}ul~>;Jb3W3hpq>2B4TMl1u4bVOIRq`%p{E@JLya!-O^h< z2}KG*k6NKE1;vAZfd9u_rBeR@FM{BkWLwsOH+k>n&3oVX&G2T^MzCIf`@MBW5c;8m z*;Rw!5t#f88$}eyD8VjHh)b}JNnA+`*C_l-Tun^ZEPNxjlA2p9{AyfJY}dw!VQNw< z#I#21)Q)h3Y2%>cHdy18Lmk?rtpmacGxu?TX`2}Vp&i_;Wo4KMy51~n1`PQmx4*T zX$4jHs`7gD0;CJD4iSssulKsj3OtzsE1@9>Eu!0!+p!n>TP&IMxk!WtrrJIq2T|Ck zUgnKFkfW+gyHb~VvR}>srG%;T)>N-jcvF 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 new file mode 100644 index 0000000000000000000000000000000000000000..0c1b3f54f80e6ce8feda9f5ff915848116179174 GIT binary patch literal 859 zcmY*X&2AGh5VpO)*=*8Kp&obw_Ru^)g%F~MazGJMB#^8~D`)K{PVL=dJ0(R$0>L%! z07qVFubg-QE?i)|jcD*{$De0Mv-5qQo53JMu+Fx>mW&|u!yoon1cxW^+Dix=ajcNW z6l0HxB08W!hXWPrh(;X_Rjd=5bU0F}?$I7b0*hpo@t7wP^K?sSUqn3NiRkm*HlR7r zc>fEc1D^8%>_a}BqT=8u{1p|r9aKgzCrVK-WGx^u;-XT_Fek4>IcL`Aax1KrO|995 zFmO(-a8A|>3pjiVHS}J!6xBs(nHHs6LQDR3P`C~7LDr>Ig|RkBvH%z6UbENf~T2)WXi>4W4Y zeC??Z&`VDpvr9tMj^&y0cz(VaTlab?K{|i@J^Mll`56v}6yxCnw|$LF5k*Tfr<_u9 zMO38NccK{3E#nbHTf&)&Z^*Fq3w_Cu`tCbv;Rc*5s;SL`@sJoEE^ymV$bfLF2#-D! zU=S-hu4U9n*2uV#twy#Rc{C1y64gOKoo&QhDn%g2KG|3Iol;Ll2`ealS4k%)2u&r5XVQr^OlDf&{nvH}8{XFosPx2wS=E8BUKr3`$vN;B)`hfot&RGpcN}%y`^iD? zisAqx#LXW1d)%W-UELPbhj;|l>UtRaM2JvF2%icu*J@b?y(`4Gr7WA91bxMAQNj;m z!t?IfpEvK{W|#N(*;U~_EGHk0{tCIX8P4TQmSEgjXsyU0%XcL+TR+@rvGMI1MGte? z@FNnEP}4=_de}DYP~j-B1es^n8Q&K|R+V}4 tXm^i&^V7vf$;uVEXmD8*?c;s&WP57&xr9%~^_Nb93_3brW+^i%N8hQ;W(nlT%|dQ{vN8^HPfvOY)0i;^Q;(GE3s)^$IF) gaoFVMrV!Z diff --git a/id_generator/__pycache__/generator.cpython-312.pyc b/id_generator/__pycache__/generator.cpython-312.pyc deleted file mode 100644 index 3ef7f83d9b0a67a9d194a42baf8bea9652cc7fa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1533 zcmZux&2Jl35PxsiAM1}a!GTIn8rT*>YD7XJaiKyHL7`C&1f-}vSdpGwzvp({wKu$7 zQ*1?5s4SEsK{!Cu!hv#v5-AjM;8gktaB;{X)e25DAH9Vdgv5!NUGLVE%wgWlyqWiA zelzd=+|!dJKzHWPUP!2f{EkXMk&e)Q8H6>$NuF@Z6_Zw!yh2e{L00oBB?_4#JklgQ zx~}+9`A9vMi`PzomVEHVxBDM{zqhfr`@?5@pMJT!^2yGPZ)W+7s0vwdESY>j!7WGK zxV7jQR@DYEZC9;JC9`l*u*yWyKhx)(3rPEQ(AS6{c?zj1oaR-oG)X?fRS_+xyF+}r zq(F+1e4Iyx267DKL_MC<+|0Bn6>6r_l~U~~h)L=|v(sV9o?gUU1HxPYHqy=jLx`3L z3-(AIN}7XG5@9K~s2j0`S+emA{h!m*rxxCpR#_Asdtt_KF4WG2s%f1cEto<&qqdOm z8bz^SaCSaGY$24!7VECYm{Bzx#u|hFuVgIP#1!oWuw`;DJG2t{=tvt=bz?s0#Q;|{ zVohFMCJ1X}iI&m&7;$kZc9Nu%#v!4|q>RD>?1wB*=aF6t)G z$k6B}&lb#@cmua2-sh&~VZct~fW0{(HL&CqiElw30cIl@x-L_&xP7*8SU38OXAgn- zaVH!gdmPv@IY^RpW;->wnHs!a`X%+;ubE@5p_jHY?_z6 z*@KtHq;P7o`k!eFyTZW(xRxaE>gB7Kw|j>-dxy7r zM_Ss52kBfci7%yEs0hZ~Bx4ne*G!btjJ;DUn4O(CW85k-Ch-fAh`F2T`WfExzbM&{ z8>&%tyqs?l?+(8RoOg)~J88cFtV#Y*l&JPlqtT}iVp{an%}d)OQ=21GZ34={lkw=u z>-~QcSo~u!7zS7l!0P%*cvI`0Du=-O=sH(>)vshyB0Bg0?PI_WR7xpaOCx{v5qk7D QGVpgSOHV!|z`W>x0jFSbZvX%Q diff --git a/id_generator/__pycache__/options.cpython-312.pyc b/id_generator/__pycache__/options.cpython-312.pyc deleted file mode 100644 index 781eaf9a7977dbc3bf5e5cdc16ba1f0d24cdd1f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1142 zcmaJ=O=uHA6rSB|(ll*@+Jdzex>m&oOz(<%DwJN@g5V(rh9omKt4X$<-K|z~$RU-8 z4eg;)^x)5}B33{6@vVBdbY}k&t#5BMN_QJi-$pX+jICEY0crLFT_c<%Bq$*>DG^`_lgm;re1;=1#?krGQt8KpUi#XLM_0@F<)V8ZT_g}Sh7<}%3 zYG-TNsjNB6Z~mpuc+JOFVW$G{G)-`D5mJ#*K&~+vnB=h{#=OpwBF0eJvSI+3pO+yE zdNHN|g8^`j1%Y*VY=Oi=lMO79!(7wq)r;?g4U9HWuYH1@v9KM=b2F$j~*?m6T*AqMXXOHY?K6Q)YTEWVvxd5&e_VZp-pQZXd+-ycSOmJ4gj48Ha@Z2?l zlPtQ>b%QhTOL0Vgjg6g8P7D1y&zMGXTr;y)+NU{vCZ5W1Va5$E=Cuq@YK+c!!<*FI zc^jQwu)~yU1(*eTd+_gp9QA^SvGNqS64?!rqx}_SsSCis830iPC)?okxr*{Rd;*q+ z;)n)!!(>Q3h(hGlNJaS)R-2HLOvVBN@2G)J^nrul1I|@QR diff --git a/id_generator/__pycache__/snowflake.cpython-312.pyc b/id_generator/__pycache__/snowflake.cpython-312.pyc deleted file mode 100644 index 6fca833ce64b1ffd86686d8c597b74bd61bf9dc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 735 zcmY*X&ubG=5T3U`l5|P5X$3D*Lp|-G{R2cil@>2SDD@Bmk9GH@UES{1x4UXe4?W~i z1XB;%t$OfK1b={3Jb3ai@E?%9N|N>#8$s~oOg4#hV88dxo0;#;?0er!B?HjDt=`#~ zX8=FR8JjjDgDXf9aG(YXtboH>;3yxJELvkt)zso^=ozQ4Kb$=I-20Stzr5%@f79K2 z)_M7^+kV^GKk6JEcMsc!J(3(QBLx`Dp__n!8pAUb(yytGBD99$s4cCgH#JjFr&j&o z(XwaV7xuW2REVqi4Q3D$*kL=sk!98dlT}TY=7X)s4gAnlQY{o-L+Th0skBo0yS#M0 zep?3jgdK(T6*t<5?@nAVSYNO_A)|#*$cL^i>aN4rg)gKP1+pGuOATsiajTgYICp(F z;(U8%((2-PuSf?@A?(7B%X53$)8YUfNOMv|vGi^H_vdUl5?w$7O=c?bJW``FvXl1L z&i+C7;JEjywYGL^X%aXkjrTaT%pnO$v?B9}Y2Fu)Bknre<^R2nwk}dCCGA4rfa$WN zHmhci2J)>iUtqfJ~MMsD5~=q$!3#k1U);Xu+Ar z^sD`xu9pvIe*-RAKBZRie)60tBkQa{(*`S_ I0m4xA9}r-)ApigX diff --git a/id_generator/__pycache__/snowflake_m1.cpython-312.pyc b/id_generator/__pycache__/snowflake_m1.cpython-312.pyc deleted file mode 100644 index 9e662f0ecc6ca439501403b4328a0b490a1c04a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6929 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 int: - """ - 获取新的UUID - """ - - if self.snowflake is None: - raise ValueError("please set id generator at first.") - return self.snowflake.next_id() diff --git a/id_generator/idregister.py b/id_generator/idregister.py deleted file mode 100644 index 787faac..0000000 --- a/id_generator/idregister.py +++ /dev/null @@ -1,134 +0,0 @@ -""" -worker id generator -""" - -# !/usr/bin/python -# coding=UTF-8 - - -from threading import Thread -import time -import logging -import redis - - -class Register: - """ - redis封装 - - host 代表redis ip - - port 代表redis端口 - - max_worker_id worker_id的最大值, 默认为100 - - password redis的密码, 默认为空 - """ - - def __init__(self, host, port, max_worker_id=100, password=None): - self.redis_impl = redis.StrictRedis(host=host, port=port, db=0, password=password) - self.loop_count = 0 - self.max_loop_count = 10 - self.worker_id_expire_time = 15 - self.max_worker_id = max_worker_id - self.worker_id = -1 - self.is_stop = False - - def get_lock(self, key): - """ - 获取分布式全局锁,并设置过期时间为30秒 - """ - - if self.redis_impl.setnx(key, 1): - self.redis_impl.expire(key, 30) - return True - if self.redis_impl.ttl(key) < 0: - self.redis_impl.expire(key, 30) - return False - - def stop(self): - """ - 退出注册器的线程 - """ - - self.is_stop = True - - def get_worker_id(self): - """ - 获取全局唯一worker_id, 会创建一个线程给worker id续期 - 失败返回-1 - """ - - self.loop_count = 0 - - def extern_life(my_id): - while 1: - time.sleep(self.worker_id_expire_time / 3) - # 是否关闭了 - if self.is_stop: - return - # 更新生命周期 - if self.worker_id != my_id: - break - try: - self.redis_impl.expire( - f"IdGen:WorkerId:Value:{my_id}", - self.worker_id_expire_time) - except Exception as exe: - logging.error(exe) - continue - - self.worker_id = self.__get_next_worker_id() - if self.worker_id > -1: - Thread(target=extern_life, args=[self.worker_id]).start() - return self.worker_id - - def __get_next_worker_id(self): - """ - 获取全局唯一worker id内部实现 - """ - - cur = self.redis_impl.incrby("IdGen:WorkerId:Index", 1) - - def can_reset(): - try: - reset_value = self.redis_impl.incr("IdGen:WorkerId:Value:Edit") - return reset_value != 1 - except Exception as ept: - logging.error(ept) - return False - - def end_reset(): - try: - self.redis_impl.set("IdGen:WorkerId:Value:Edit", 0) - except Exception as ept: - logging.error(ept) - - def is_available(worker_id: int): - try: - rst = self.redis_impl.get(f"IdGen:WorkerId:Value:{worker_id}") - return rst != "Y" - except Exception as ept: - logging.error(ept) - return False - - if cur > self.max_worker_id: - if can_reset(): - self.redis_impl.set("IdGen:WorkerId:Index", -1) - end_reset() - self.loop_count += 1 - - if self.loop_count > self.max_loop_count: - self.loop_count = 0 - return -1 - - time.sleep(0.2 * self.loop_count) - return self.__get_next_worker_id() - time.sleep(0.2) - return self.__get_next_worker_id() - if is_available(cur): - self.redis_impl.setex( - f"IdGen:WorkerId:Value:{cur}", - self.worker_id_expire_time, - "Y" - ) - self.loop_count = 0 - return cur - - return self.__get_next_worker_id() diff --git a/id_generator/options.py b/id_generator/options.py deleted file mode 100644 index 8558381..0000000 --- a/id_generator/options.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -生成器IdGenerator配置选项 -""" - -# !/usr/bin/python -# coding=UTF-8 - - -class IdGeneratorOptions: - """ - ID生成器配置 - - worker_id 全局唯一id, 区分不同uuid生成器实例 - - worker_id_bit_length 生成的uuid中worker_id占用的位数 - - seq_bit_length 生成的uuid中序列号占用的位数 - """ - - def __init__(self, worker_id=0, worker_id_bit_length=6, seq_bit_length=6): - - # 雪花计算方法,(1-漂移算法|2-传统算法), 默认1。目前只实现了1。 - self.method = 1 - - # 基础时间(ms单位), 不能超过当前系统时间 - self.base_time = 1582136402000 - - # 机器码, 必须由外部设定, 最大值 2^worker_id_bit_length-1 - self.worker_id = worker_id - - # 机器码位长, 默认值6, 取值范围 [1, 15](要求:序列数位长+机器码位长不超过22) - self.worker_id_bit_length = worker_id_bit_length - - # 序列数位长, 默认值6, 取值范围 [3, 21](要求:序列数位长+机器码位长不超过22) - self.seq_bit_length = seq_bit_length - - # 最大序列数(含), 设置范围 [max_seq_number, 2^seq_bit_length-1] - # 默认值0, 表示最大序列数取最大值(2^seq_bit_length-1]) - self.max_seq_number = 0 - - # 最小序列数(含), 默认值5, 取值范围 [5, max_seq_number], 每毫秒的前5个序列数对应编号0-4是保留位 - # 其中1-4是时间回拨相应预留位, 0是手工新值预留位 - self.min_seq_number = 5 - - # 最大漂移次数(含), 默认2000, 推荐范围500-10000(与计算能力有关) - self.top_over_cost_count = 2000 diff --git a/id_generator/snowflake.py b/id_generator/snowflake.py deleted file mode 100644 index ea36cfa..0000000 --- a/id_generator/snowflake.py +++ /dev/null @@ -1,20 +0,0 @@ - -""" -雪花算法生成器接口声明 -""" - -# !/usr/bin/python -# coding=UTF-8 - - -class SnowFlake(): - - def __init__(self, options): - self.options = options - - def next_id(self) -> int: - """ - 获取新的UUID - """ - - return 0 diff --git a/id_generator/snowflake_m1.py b/id_generator/snowflake_m1.py deleted file mode 100644 index 596b76d..0000000 --- a/id_generator/snowflake_m1.py +++ /dev/null @@ -1,147 +0,0 @@ -""" -M1生成器 -""" - -# !/usr/bin/python -# coding=UTF-8 - -import threading -import time -from .snowflake import SnowFlake -from .options import IdGeneratorOptions - - -class SnowFlakeM1(SnowFlake): - """ - M1规则ID生成器配置 - """ - - def __init__(self, options: IdGeneratorOptions): - # 1.base_time - self.base_time = 1582136402000 - if options.base_time != 0: - self.base_time = int(options.base_time) - - # 2.worker_id_bit_length - self.worker_id_bit_length = 6 - if options.worker_id_bit_length != 0: - self.worker_id_bit_length = int(options.worker_id_bit_length) - - # 3.worker_id - self.worker_id = options.worker_id - - # 4.seq_bit_length - self.seq_bit_length = 6 - if options.seq_bit_length != 0: - self.seq_bit_length = int(options.seq_bit_length) - - # 5.max_seq_number - self.max_seq_number = int(options.max_seq_number) - if options.max_seq_number <= 0: - self.max_seq_number = (1 << self.seq_bit_length) - 1 - - # 6.min_seq_number - self.min_seq_number = int(options.min_seq_number) - - # 7.top_over_cost_count - self.top_over_cost_count = int(options.top_over_cost_count) - - # 8.Others - self.__timestamp_shift = self.worker_id_bit_length + self.seq_bit_length - self.__current_seq_number = self.min_seq_number - self.__last_time_tick: int = 0 - self.__turn_back_time_tick: int = 0 - self.__turn_back_index: int = 0 - self.__is_over_cost = False - self.___over_cost_count_in_one_term: int = 0 - self.__id_lock = threading.Lock() - - def __next_over_cost_id(self) -> int: - current_time_tick = self.__get_current_time_tick() - if current_time_tick > self.__last_time_tick: - self.__last_time_tick = current_time_tick - self.__current_seq_number = self.min_seq_number - self.__is_over_cost = False - self.___over_cost_count_in_one_term = 0 - return self.__calc_id(self.__last_time_tick) - - if self.___over_cost_count_in_one_term >= self.top_over_cost_count: - self.__last_time_tick = self.__get_next_time_tick() - self.__current_seq_number = self.min_seq_number - self.__is_over_cost = False - self.___over_cost_count_in_one_term = 0 - return self.__calc_id(self.__last_time_tick) - - if self.__current_seq_number > self.max_seq_number: - self.__last_time_tick += 1 - self.__current_seq_number = self.min_seq_number - self.__is_over_cost = True - self.___over_cost_count_in_one_term += 1 - return self.__calc_id(self.__last_time_tick) - - return self.__calc_id(self.__last_time_tick) - - def __next_normal_id(self) -> int: - current_time_tick = self.__get_current_time_tick() - if current_time_tick < self.__last_time_tick: - if self.__turn_back_time_tick < 1: - self.__turn_back_time_tick = self.__last_time_tick - 1 - self.__turn_back_index += 1 - # 每毫秒序列数的前5位是预留位, 0用于手工新值, 1-4是时间回拨次序 - # 支持4次回拨次序(避免回拨重叠导致ID重复), 可无限次回拨(次序循环使用)。 - if self.__turn_back_index > 4: - self.__turn_back_index = 1 - - return self.__calc_turn_back_id(self.__turn_back_time_tick) - - # 时间追平时, _TurnBackTimeTick清零 - self.__turn_back_time_tick = min(self.__turn_back_time_tick, 0) - - if current_time_tick > self.__last_time_tick: - self.__last_time_tick = current_time_tick - self.__current_seq_number = self.min_seq_number - return self.__calc_id(self.__last_time_tick) - - if self.__current_seq_number > self.max_seq_number: - self.__last_time_tick += 1 - self.__current_seq_number = self.min_seq_number - self.__is_over_cost = True - self.___over_cost_count_in_one_term = 1 - return self.__calc_id(self.__last_time_tick) - - return self.__calc_id(self.__last_time_tick) - - def __calc_id(self, use_time_tick) -> int: - self.__current_seq_number += 1 - return ( - (use_time_tick << self.__timestamp_shift) + - (self.worker_id << self.seq_bit_length) + - self.__current_seq_number - ) % int(1e64) - - def __calc_turn_back_id(self, use_time_tick) -> int: - self.__turn_back_time_tick -= 1 - return ( - (use_time_tick << self.__timestamp_shift) + - (self.worker_id << self.seq_bit_length) + - self.__turn_back_index - ) % int(1e64) - - def __get_current_time_tick(self) -> int: - return int((time.time_ns() / 1e6) - self.base_time) - - def __get_next_time_tick(self) -> int: - temp_time_ticker = self.__get_current_time_tick() - while temp_time_ticker <= self.__last_time_tick: - # 0.001 = 1 mili sec - time.sleep(0.001) - temp_time_ticker = self.__get_current_time_tick() - return temp_time_ticker - - def next_id(self) -> int: - with self.__id_lock: - if self.__is_over_cost: - nextid = self.__next_over_cost_id() - else: - nextid = self.__next_normal_id() - return nextid diff --git a/logs.db b/logs.db index 763fad305eeb62fff6a0a3735804afbd6fd50f24..6c380f9c947e82e2b930c8ccb42b72851990974c 100644 GIT binary patch literal 53248 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 b6n_4n|Ko!3{(pG?Km7c^O$ZJ3@GJfgLA^ZT delta 204 zcmZozz}%29L7J6`fq{W}qJq636N6rxCNGf3#CL>&Uxx322PC~$G+7ixbmR6+&DiLO}fD{L-T2RJbZb1BkNZ{JfIXijv9m`Q;@7f;@d4gCZ5YT_Y7V aGE+3Uzz$;&06M9be_}%|8yC=>2rdAht~6-? diff --git a/models/__pycache__/base.cpython-312.pyc b/models/__pycache__/base.cpython-312.pyc deleted file mode 100644 index bb5d27c68e0bf52b77c8e78be6fd9c8f2c1a0352..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2066 zcmZux&2Q936d&8WUa$8nY(faMK-6vv+k_md3aJ6LDnyMCC4ibstJ^k6IJT$$0lg3rDRk5ds)_@*v`H^L^^F~GmMSCp`Mr5>-pqUN z_uen1l8Ioo&;Px+l|krFDWogA%WRJ;2(2K3h~gn%u@qmmR9~|+KVxMSxvzRzU$=BW zXXRp9^9UiV6V*(&=LtD+zk(Qu69J|ZSHSG7cM4T0xO^Syme4v_*Wu9Z?t zQofIRw++X>D&T8?4y6{>q0WJN^_6s0&j|f|=(YVonCINag@DrrWx|-UIh}QVDzfw@ z4R~D@B|;s~W|Ux?b0!87(dO<=is$W!))iq8IK|-<@R@VTUfHpI>R}$@D6p?naFh#M z+zo?Bq~;s$<(t#zd+=hX5k5i7IS@@b?|lC5m`4N^tQ8G!T4U8bNOwL#~1RR?k;Mo zvBhg7t=#A6kupWC7?+@AMn;`q)`64AtKyTfozGzg@Nc62mw?1A%x z_r3SDGWNt6+lFm4Q_nMLButFKf7^pMiXz50+P0TCmXbXmab`OlV5ADsln6%>k8lP3XSeYC(sXP8bAGL_o68xy>4sNAgXh zqoZ*~#PDm;V9$-XggZM4Mn~a`60<^H>C+NwkVEGr*(Q~r}Sae3NMM$q;= ziA<3rbirn5R*k>c_2ay!ds%?FbYSo z94MlYoR0-|TpI3SPtHUpNe#Z}10X5(sv{3Z9!~vu^5^lN#y6_d-HX5W?>xEs#pcy( z>sPOBRKL7;F>xr}%+yDO8Qt(~&sn5?XAl1@exa;^II^do0BlV3O~a%^46sUqsQ^+I z+{OgNZ_7qzrgTtjbJvR|oY42fAek6Nm*Cz=WJT$qBu%Rq$aFd>FYnII>Qs{EJ{5ag z8V^KNBDK#^+*^eNe-VZbiy;^%?0=aQ#@S>be8eWfmmFBp*Fd&3MNyuk$){-YIr{V^ zI{Ffg{*F#OM`K$$D!j9FV$-axo3)2*!+gJ+duG&@@|#9&-Kae^-tA_eq3k9aUPr^r zw>Hr69m7z@mu7bm{I*7rI@mq9sZ`gM>hkFaA3r7=${837N(}~tdUi{4JH?EGm1X@O JB>!=h{sWIS;f4SJ diff --git a/models/__pycache__/log_alert.cpython-310.pyc b/models/__pycache__/log_alert.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a77da786a92ea1492acf148ce5168edc889c4588 GIT binary patch literal 896 zcmYjQ&2H2%5VoB^Z+5r4Ko1D|0y(q?j(||1l?oE7klK^AlI5<=HpNc1j#GBe%eAk8 z#1rry9DU`~2jIeqaZ<5$2KaViuc(B_?HQ7mIXeD5DrDx*$S)ZOcTUHAnpR1Mg^cYglLn`)DspeW(;mRAuFGQo} zf$!l+0UW|?ZonwSutbbV%pw)5L=t$S+lZxrG8u311~VEWunz9m9M&P=QI`V|nab>z zurc5rNz~+ODk*S0+T!lr;5KHDWezHbo_?$sZ?&?H<+@&Q5!~jyAbz;Cr4e?`zo@lO z%1Wx$-3zGnZWoNtma3AV9F%5KeHN{Du!mNy*5U#&>3<8Z1nDqpJSOhI6Z+Iv%#MVP9$oejxiiqz3c%)$z;O(P}k2 zDc$?_;*+hf)Z8^Q=-htSx&21jn{uvZAWG>j(6{tpxwZpf2(t+tq$tKaWP~ZEgyJcl zlBc-KI4y>KS$T7V?a!Gl|8DSXDq@8Irr#9JA?w->_n Vb>IFsI20Csw-MTdvQn}e{R5Io>XHBe literal 0 HcmV?d00001 diff --git a/models/base.py b/models/base.py deleted file mode 100644 index d35671e..0000000 --- a/models/base.py +++ /dev/null @@ -1,40 +0,0 @@ -from sqlalchemy import Column, BigInteger, DateTime, event -from sqlalchemy.ext.declarative import declared_attr, declarative_base - -from datetime import datetime - -from config.database import Base -from utils.common import camel_to_snake -from id_generator import options, generator - -# https://github.com/yitter/IdGenerator/tree/master/Python -options = options.IdGeneratorOptions(worker_id=23) -idgen = generator.DefaultIdGenerator() -idgen.set_id_generator(options) - - -# 第二层基类:包含ID -class IdBase(Base): - __abstract__ = True - - id = Column(BigInteger, primary_key=True, index=True) - - @declared_attr - def __tablename__(cls): - # 自动把数据库实体类名驼峰转为数据库表名下划线 - return camel_to_snake(cls.__name__) - - -# 自动填充id -@event.listens_for(IdBase, 'before_insert', propagate=True) -def before_insert_listener(mapper, connection, target): - if target.id is None: - target.id = idgen.next_id() - - -# 第二层基类:包含ID和审计字段 -class AuditBase(IdBase): - __abstract__ = True - - create_time = Column(DateTime, nullable=True, default=datetime.now) - update_time = Column(DateTime, nullable=True, default=datetime.now, onupdate=datetime.now) diff --git a/models/log_alert.py b/models/log_alert.py index 6d8f97e..791d8ad 100644 --- a/models/log_alert.py +++ b/models/log_alert.py @@ -1,7 +1,8 @@ -from sqlalchemy import Column, Integer, String, DateTime, Text -from sqlalchemy.ext.declarative import declarative_base from datetime import datetime +from sqlalchemy import Column, Integer, String, Text, DateTime +from sqlalchemy.ext.declarative import declarative_base + Base = declarative_base() @@ -9,9 +10,12 @@ class LogAlert(Base): __tablename__ = "log_alerts" id = Column(Integer, primary_key=True, index=True) - timestamp = Column(DateTime) - log_level = Column(String(20)) + alter_name = Column(String(50)) + alter_timestamp = Column(Integer) + + timestamp = Column(Integer) message = Column(Text) - source = Column(String(100)) - context = Column(Text) # 存储JSON格式的上下文信息 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 36adcf2..ad92be6 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 \ 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 \ No newline at end of file diff --git a/schemas/__pycache__/log_alert.cpython-310.pyc b/schemas/__pycache__/log_alert.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c2bf8a96370d14b3af5e2627deda178133592ad GIT binary patch literal 795 zcmZva&2AGh5XbHPNOrdg%^|=I<+@1a)DwzO3#dT|0tmRQB3W)cO&580Q`%aioP<4AyItFAjNMq#oyt!iQj$KtqwI9_r=t!6_~1!+JO)($R|wg*os+KaT1(Nobw8OI;DLhtnZAC$ zcy)fhnAPsh=J=!OzQNMjh3-~+k`A+H!F;cmu&~QhXk^HUka@P=8p27__D~9z@c|F9 z|4`g=e~X3ppdciO0#X$d^Q)-p1x!7})35r$&d|=Q405b3(B46813&t(hPFGVW5TBm zn5{36lW~HG`3zbWEQ8&^d~#yC2H&o);6!e;^QqLev_7S{xTfCmiLEc-;-LkNBqmQM zl$!jjkL{VBmxZDGnm$QJvO_|v4ZXP;lRP4MOp=q_BEPYQ6nlU|NlQt>m+>(o9PyBu nm#NRzTP0gpFHJ-X!tTT}6x_F`&!#sG@q#WK-etr_@i_epsyMb2 literal 0 HcmV?d00001 diff --git a/service/__pycache__/log_alert_service.cpython-310.pyc b/service/__pycache__/log_alert_service.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6c1bb9334ecca2df98fd010af73f37262b71edf GIT binary patch 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 literal 0 HcmV?d00001 diff --git a/service/__pycache__/message_service.cpython-310.pyc b/service/__pycache__/message_service.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fabce2867068222fb7d9ed1534df6db042d5119 GIT binary patch literal 1092 zcmZWoOK%e~5VpPE%_iBTp_LFl@VIbTq!y_sgb*sUrAVj&K_t*B(rQ_|$tL?qZEs&{ zPgLCc4>-V)1HXa);VUP802jo8@n$0`Vael}`8*GMW{OUyg<#$N_G|pzLgn#ZewK7u-hQceERZd6e-m)U7bg3Rb3u_rma?jM5sRgPnH+ z?e0B!{bKv&+rDltxQ(w!bRdLqaJY4RJlsvx^YZ;GQA~KOwUDLmX*04so=dRucBYXdMo?M1U$n#7Sxiv0dW7P+>j{Nx!lk;ijc3LZu> zPLfl*RQqcWd`maRJYrl(?aU$(Wl~cXsc7JP)gKEp2BK|<2SmGqACz1wxHc=K66SyP z@)3{6kqVFa`*BfB!&0RG=^zPBt9)!$W-|!K^SEH#x5Se1-UAYJYe#h@|8%HfOnd+a7&xAsmbTCL{^&`1@ArO|>h}|Z^8L%N#helH!!K@2gp22>W*?0pf|exp zo|Uv>DWg6P%An#YZ)0ADRg^{;htLrbY6s$zNW`N1nWtSr-;zP{6Kj#f0d@U@$>eA+ zGe!QQu?tMZ2COaQ++e)*x(2C^4e0mqrUAWjiLsfsGh0;PVvu4JMH+0QWsdOwOMp>~ zIz~0SXe?P$%a(zl__41{1eUMKnhJi-F2YMvP#fWX2Q~i0M0n0WvNgNtUJ?Wx9iDAv zbzK&DW(y^sERB)_=Atamp|)qev62>~9Zps?xbU6FI$%1)w%YSI2wZ0YnE-7Z_jeu7 z{J4pWHQ;GuF<&cVwTGQPP&aeW8eM9RS(j8wKsgglRck+K`smIvWJzWf+|AaRF&~r` z`d*9T29a-UY9$SPBYGP*|LnhfIvt;$PG1%FpgBI$Y6-bD(^AccSqa(>{ck98m|pwa z-LG<^dgVHEurs{n$u~P_IOUWvM)}_z-lNg)IMEM1nnd@}x&Ac+BTva@virG`C&hep z^%h!I+_uRVP-SL>#b+&~4KG0 bool: + start_time, end_time = get_timestamp_range(log_alter.timestamp, 60) + result = openobserve_service.get_log(start_time, end_time) + hits = result.get("hits") - url = 'http://192.168.1.7:5080/api/default/_search' - username = 'njcxx0822@163.com' - password = '19940822Cxx' + # 判断日志是否为空 + if len(hits) == 0: + return False - response = requests.post( - url, - headers={ - 'accept': 'application/json', - 'Content-Type': 'application/json' - }, - json={ - "query": OpenobserveQuery( - start_time=1760773184953420, - end_time=1760773189953431 - ).model_dump() - }, - auth=HTTPBasicAuth(username, password) + # 判断日志告警是否已经存在 + log_db_alter = db.execute( + select(LogAlert) + .where(LogAlert.alter_timestamp == log_alter.timestamp) + ).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) + + +def batch_insert(log_alter: LogAlertTrigger, hits: [], db: Session) -> bool: + stmt = insert(LogAlert).values( + [ + { + "alter_name": log_alter.alter_name, + "alter_timestamp": log_alter.timestamp, + "timestamp": hit["_timestamp"], + "message": hit["message"], + "status": "pending" + } + for hit in hits + ] ) - return response.json().get("hits") + db.execute(stmt) + db.commit() + + return True + + +def query_alert(db: Session): + alerts = db.execute(select(LogAlert)).scalars().all() + + # 按照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 + }) + + return dict(classified) diff --git a/service/message_service.py b/service/message_service.py new file mode 100644 index 0000000..c10d057 --- /dev/null +++ b/service/message_service.py @@ -0,0 +1,32 @@ +import json +from enum import Enum + +import requests + +from config.setting import settings + + +class MessageEnum(Enum): + TEXT = 'text' + MARKDOWN = 'markdown' + MARKDOWN2 = 'markdown2' + + +def send_wechat_message(message_type: MessageEnum, message: str): + wechat_message = {} + match message_type: + case MessageEnum.TEXT: + wechat_message = {"msgtype": "text", "text": {"content": message}} + case MessageEnum.MARKDOWN: + wechat_message = {"msgtype": "markdown", "markdown": {"content": message}} + case MessageEnum.MARKDOWN2: + wechat_message = {"msgtype": "markdown_v2", "markdown_v2": {"content": message}} + + requests.post( + 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') + ) + + return True diff --git a/service/openobserve_service.py b/service/openobserve_service.py index 961d813..14ef81b 100644 --- a/service/openobserve_service.py +++ b/service/openobserve_service.py @@ -1,27 +1,19 @@ import requests from requests.auth import HTTPBasicAuth +from config.setting import settings from schemas.log_alert import OpenobserveQuery -def get_log(): - url = 'http://192.168.1.7:5080/api/default/_search' - username = 'njcxx0822@163.com' - password = '19940822Cxx' - +def get_log(start_time: int, end_time: int) -> str: response = requests.post( - url, + settings.openobserve_url, headers={ 'accept': 'application/json', 'Content-Type': 'application/json' }, - json={ - "query": OpenobserveQuery( - start_time=1760773184953420, - end_time=1760773189953431 - ).model_dump() - }, - auth=HTTPBasicAuth(username, password) + json={"query": OpenobserveQuery(start_time=start_time, end_time=end_time).model_dump()}, + auth=HTTPBasicAuth(settings.openobserve_username, settings.openobserve_password) ) - print(response) + return response.json() diff --git a/utils/__pycache__/time.cpython-310.pyc b/utils/__pycache__/time.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef6824413006460e849bc98412061764fe35a44a GIT binary patch literal 899 zcmY*Xy-yTT5P$FO+r0(u1O*XeL*W%$oSn^S3=tD)B*wGxatT@Yy**d=3y#OALidVdtN)tsLA{RyM}Mc?(ByHZwajZ{E!OW?ob(^&_C<`|o=@ z1fieGI8Fm#OaRBXKrqCxj{;OjSn0&a0jU$v2bs<_W&jsBWhN(Fudl{O-^0PimbFi>jpbfL)K6i@*)doCbK1%Ucf=uZznCEcXc?)ih<{dDCSNSvN$6$ z&Pt5?(w^zLXcBrdGX$532pvtOJ0x{q@g#6u1(8Dk53n#8sUfB@%5-M1!dtq5Qo{62 zGOwjL)ke@fO;Jk6AU>sMkPFe4nbaUb|2R-*=XHDi-QMcw?&{Xw;-~h~a{I-~e?9Gg zc)7o}(0Tr(y}tG9%VK-^&FjBH}qfi^AFb9{8Ne5X6YzLZR&qrY9F@q-SPEB}78a-B zJjZ+>hE@2G8;QU^hGY!9vC1@ph0>>CF{-b8%vRx`h#}`%Uf2}ssb!iM%1nbgIllbT eu_|iDA}?iL4kDKL{EC7atA!L%5uevahyMYebnkrt literal 0 HcmV?d00001 diff --git a/utils/time.py b/utils/time.py new file mode 100644 index 0000000..0aac705 --- /dev/null +++ b/utils/time.py @@ -0,0 +1,25 @@ +from datetime import datetime +from typing import Tuple + + +def get_timestamp_range(ts: int, delta_seconds: int = 5, unit: str = "microseconds") -> Tuple[int, int]: + """ + 返回时间戳前后delta_seconds秒的范围(单位与输入一致) + """ + if ts <= 0: + return 0, 0 + + scale = { + "seconds": 1, + "milliseconds": 1000, + "microseconds": 1_000_000, + "nanoseconds": 1_000_000_000 + + }.get(unit, 1_000_000) # 默认微秒 + + delta = delta_seconds * scale + 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")