Skip to content

Commit 5afd370

Browse files
committed
testing for v2.9, upgrade Operations system with alerting, custom metrics, events, actions and user reports, fix bugs in env file parsing and functional utils
1 parent a0f4747 commit 5afd370

56 files changed

Lines changed: 5814 additions & 1841 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/zh/community/roadmap.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
### 运维管理系统
2626

27-
* 服务端自定义或推送报警规则进行实时报警通知
27+
* 服务端自定义或推送告警规则进行实时告警通知
2828
* 支持接入现有的日志与监控数据源(如 ElasticSearch 与 Prometheus)
2929
* 对测试场景服务端能力的完善,如测试库,测试日志,压测处理
3030

@@ -36,4 +36,4 @@
3636
**新特性**
3737

3838
* 支持部署所需的 uwsgi 和 gunicorn 配置文件的自动生成
39-
* 支持服务端自定义或推送报警规则进行实时报警通知
39+
* 支持服务端自定义或推送告警规则进行实时告警通知

docs/zh/guide/config-run.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,6 @@ nginx -s reload
789789

790790
## 服务观测与运维管理
791791

792-
UtilMeta 框架内置了一个 API 服务管理系统,可以方便地观测与管理对本地与线上的 API 服务,提供了数据,接口,日志,监控,测试,报警等一系列运维管理功能,在 [Operations 运维管理系统配置](../ops) 中有这个系统的详细介绍与配置方式
792+
UtilMeta 框架内置了一个 API 服务管理系统,可以方便地观测与管理对本地与线上的 API 服务,提供了数据,接口,日志,监控,测试,告警等一系列运维管理功能,在 [Operations 运维管理系统配置](../ops) 中有这个系统的详细介绍与配置方式
793793

794794
你也可以直接进入 [UtilMeta API 服务管理平台](https://ops.utilmeta.com) 进行体验

docs/zh/guide/ops.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 运维监控与服务管理
22

3-
UtilMeta 框架内置了一个 API 服务管理系统,可以方便地观测与管理对本地与线上的 API 服务,提供了数据,接口,日志,监控,测试,报警等一系列运维管理功能,本篇文档将详细介绍 UtilMeta 的 Operations 运维管理系统的配置与 UtilMeta 平台的连接方式
3+
UtilMeta 框架内置了一个 API 服务管理系统,可以方便地观测与管理对本地与线上的 API 服务,提供了数据,接口,日志,监控,测试,告警等一系列运维管理功能,本篇文档将详细介绍 UtilMeta 的 Operations 运维管理系统的配置与 UtilMeta 平台的连接方式
44

55
## 配置引入
66

@@ -68,7 +68,7 @@ Operations 配置项的主要参数包括
6868

6969
**任务与监控配置**
7070

71-
* `worker_cycle`:Operations 系统在服务启动后会在每个进程(worker)中启动一个运维任务线程,用于收集并存储请求日志,监控服务数据和报警等,你可以使用 `worker_cycle` 参数指定这些任务每次运行的间隔时间(`int` 描述或 `timedelata`),默认为 30 秒,也就是说默认服务每个进程的请求日志会每 30 秒持久化一次,服务器,数据库和服务实例的监控与报警会每 30 秒进行一次
71+
* `worker_cycle`:Operations 系统在服务启动后会在每个进程(worker)中启动一个运维任务线程,用于收集并存储请求日志,监控服务数据和告警等,你可以使用 `worker_cycle` 参数指定这些任务每次运行的间隔时间(`int` 描述或 `timedelata`),默认为 30 秒,也就是说默认服务每个进程的请求日志会每 30 秒持久化一次,服务器,数据库和服务实例的监控与报警会每 30 秒进行一次
7272

7373
* `max_backlog`:设置请求日志的最大积压量,除了运维任务的每个 `worker_cycle` 会持久化日志外,当你的进程中积压的未存储日志超过了 `max_backlog` 的值也会触发日志存储,默认是 100
7474
* `secret_names`:运维管理系统的日志模块会在请求出错(抛出异常,返回 400 及以上状态码)时存储请求和响应的信息用于调试,为了数据安全,你可以指定一系列可能包含密钥或敏感数据的字段名,在日志进行存储时,检测到字段名包含其中任何一个的请求参数,请求体,请求头,响应体和响应头字段都会使用 `'******'` 来代替,默认的 `secret_names`
@@ -87,7 +87,7 @@ DEFAULT_SECRET_NAMES = (
8787
)
8888
```
8989

90-
* `max_retention_time`:指定运维系统中所有时序数据的最大存储时间,时序数据包括日志,服务监控,报警记录等数据,这里指定的是所有数据最大存储时间,超过这个时间的数据会被清理,对于细分的数据类别和状态下面将会也介绍更具体的存储时间配置
90+
* `max_retention_time`:指定运维系统中所有时序数据的最大存储时间,时序数据包括日志,服务监控,告警记录等数据,这里指定的是所有数据最大存储时间,超过这个时间的数据会被清理,对于细分的数据类别和状态下面将会也介绍更具体的存储时间配置
9191

9292

9393
**管理权限配置**
@@ -293,7 +293,7 @@ UtilMeta 已经提供了一个开源的代理服务 [utilmeta-proxy](https://git
293293
在 Operations 配置中,可以使用 `proxy` 参数配置代理服务节点的地址与设置,主要的参数有
294294

295295
* `base_url`:代理节点的公网 URL 地址,在添加集群并设置代理域名后会自动生成这个地址
296-
* `forward`:是否正向代理节点的出向管理同步请求,比如同步源信息,汇报数据,报警通知等,这个参数在内网节点无法向公网地址发送请求时需要设置为 `True`
296+
* `forward`:是否正向代理节点的出向管理同步请求,比如同步源信息,汇报数据,告警通知等,这个参数在内网节点无法向公网地址发送请求时需要设置为 `True`
297297

298298
```python
299299
from utilmeta import UtilMeta
@@ -657,15 +657,15 @@ meta connect
657657
* 可调试的 API 接口文档
658658
* 编写与执行 API 单元测试
659659
* 查看 API 的调用与测试日志
660-
* 为 API 设置拨测监控与报警(即将上线)
660+
* 为 API 设置拨测监控与告警(即将上线)
661661

662662
使用 UtilMeta 框架(或其他支持的框架)连接到平台的 API 服务称为 **UtilMeta 节点**,UtilMeta 框架的运维管理系统提供的 OperationsAPI 使得 UtilMeta 节点有了服务端的观测和汇报能力,所以 UtilMeta 节点相对普通的 API 服务有着以下的额外功能
663663

664664
* 服务端请求实时日志查询
665665
* 数据管理 CRUD (需要服务端使用支持的 ORM 库,目前支持 django ORM)
666666
* API 真实请求访问统计与分析
667667
* 服务端资源性能与占用实时监控
668-
* 服务端条件报警与通知(即将上线)
668+
* 服务端条件告警与通知(即将上线)
669669

670670
!!! tip
671671
以上的功能是为提供网络访问地址的 UtilMeta 节点提供的,如果你连接的是 **本地 (localhost / 127.0.0.1)** UtilMeta 节点,那么平台只能提供数据,接口,日志,服务监控等基本功能

tests/test_5_ops/test_log.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class TestLog:
77
def test_parse_values(self, service):
8-
from utilmeta.ops.log import Logger
8+
from utilmeta.ops.log.logger import Logger
99
logger = Logger()
1010
assert (logger.parse_values([{'user': {'password': '123', 'token': 'XXX'}}]) ==
1111
[{'user': {'password': '********', 'token': '********'}}])

tests/test_5_ops/test_ops.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44
from tests.conftest import make_cmd_process, db_using
55
from utilmeta.core import cli
6-
from utilmeta.ops.client import OperationsClient
6+
from utilmeta.ops.spv.client import OperationsClient
77
from utilmeta.core.api.plugins.retry import RetryPlugin
88
# test import client here, client should not depend on ops models
99
from utilmeta.ops import __spec_version__

utilmeta/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
__website__ = "https://utilmeta.com"
22
__homepage__ = "https://utilmeta.com/py"
33
__author__ = "Xulin Zhou (@voidZXL)"
4-
__version__ = "2.8.1"
4+
__version__ = "2.9.0-alpha"
55

66

77
def version_info() -> str:

utilmeta/conf/env.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,22 @@ def _load_from_file(self) -> Mapping:
9696
if not line.strip():
9797
# empty line
9898
continue
99+
if line.startswith('#'):
100+
# comment
101+
continue
99102
try:
100-
key, value = line.split("=")
101-
except ValueError as e:
102-
raise ValueError(
103-
f"{self.__class__}: file: {repr(self._file)} invalid line: {repr(line)}, "
104-
f"should be <KEY>=<VALUE>"
105-
) from e
103+
key, *values = line.split("=")
104+
# handle = in values
105+
except ValueError:
106+
# skip other lines
107+
continue
108+
# raise ValueError(
109+
# f"{self.__class__}: file: {repr(self._file)} invalid line: {repr(line)}, "
110+
# f"should be <KEY>=<VALUE>"
111+
# ) from e
112+
106113
key = str(key).strip()
107-
value = str(value).strip()
114+
value = str('='.join(values)).strip()
108115
if key:
109116
data[key] = value
110117
return data

utilmeta/core/api/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,6 @@ def _get_route_pattern(cls):
351351
@classonlymethod
352352
def _global_vars(cls):
353353
import sys
354-
355354
return sys.modules[cls.__module__].__dict__
356355

357356
@classonlymethod

utilmeta/core/auth/properties.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class User(Property):
1818
# must be awaitable ----
1919
def get_user_id(self, request: Request) -> Union[str, int, Any]:
2020
data: Mapping = self.authentication.getter(request) or {}
21+
var.user_config.setter(request, self)
2122
if isinstance(data, Mapping):
2223
user_id = data.get(self.key)
2324
else:
@@ -28,6 +29,7 @@ def get_user_id(self, request: Request) -> Union[str, int, Any]:
2829
@awaitable(get_user_id)
2930
async def get_user_id(self, request: Request) -> Union[str, int, Any]:
3031
r = self.authentication.getter(request)
32+
var.user_config.setter(request, self)
3133
if inspect.isawaitable(r):
3234
r = await r
3335
data: Mapping = r or {}
@@ -69,6 +71,7 @@ async def get_user(self, request: Request):
6971

7072
def getter(self, request: Request, field: ParserField = None):
7173
user_var = self.context_var.setup(request)
74+
var.user_config.setter(request, self)
7275
# even if we registered factory
7376
# we still need to cache here
7477
# because parse_context will directly call getter
@@ -87,6 +90,7 @@ def getter(self, request: Request, field: ParserField = None):
8790
@awaitable(getter)
8891
async def getter(self, request: Request, field: ParserField = None):
8992
user_var = self.context_var.setup(request)
93+
var.user_config.setter(request, self)
9094
if user_var.contains():
9195
# already cached
9296
# use await in async context
@@ -130,6 +134,7 @@ def __init__(
130134
login_time_field=None,
131135
login_ip_field=None,
132136
password_field=None,
137+
last_activity_field=None,
133138
default=unprovided,
134139
required: bool = None,
135140
# context var
@@ -157,6 +162,7 @@ def __init__(
157162
self.login_time_field = login_time_field
158163
self.login_ip_field = login_ip_field
159164
self.password_field = password_field
165+
self.last_activity_field = last_activity_field
160166
self.scopes_field = scopes_field
161167

162168
self.field = field
@@ -187,6 +193,7 @@ def prepare_fields(self):
187193
self.login_time_field = self.validate_field(self.login_time_field)
188194
self.login_ip_field = self.validate_field(self.login_ip_field)
189195
self.password_field = self.validate_field(self.password_field)
196+
self.last_activity_field = self.validate_field(self.last_activity_field)
190197
self.scopes_field = self.validate_field(self.scopes_field)
191198

192199
def validate_field(self, f):
@@ -314,6 +321,8 @@ def get_update_data(self, request: Request, data=None):
314321
data = data or {}
315322
if self.login_time_field:
316323
data.update({self.login_time_field: request.time})
324+
if self.last_activity_field:
325+
data.update({self.last_activity_field: request.time})
317326
if self.login_ip_field:
318327
data.update({self.login_ip_field: str(request.ip_address)})
319328
if not data:

utilmeta/core/cli/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ async def _make_async_request(
612612
timeout: int = None,
613613
stream: bool = None
614614
) -> Response:
615+
request.adaptor.update_context(asynchronous=True) # set flag
615616
if self._internal:
616617
service = self._service
617618
if not service:

0 commit comments

Comments
 (0)