django-cfg 1.4.119__py3-none-any.whl → 1.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +8 -4
- django_cfg/apps/centrifugo/admin/centrifugo_log.py +33 -71
- django_cfg/apps/grpc/__init__.py +9 -0
- django_cfg/apps/grpc/admin/__init__.py +11 -0
- django_cfg/apps/grpc/admin/config.py +89 -0
- django_cfg/apps/grpc/admin/grpc_request_log.py +252 -0
- django_cfg/apps/grpc/apps.py +28 -0
- django_cfg/apps/grpc/auth/__init__.py +9 -0
- django_cfg/apps/grpc/auth/jwt_auth.py +295 -0
- django_cfg/apps/grpc/interceptors/__init__.py +19 -0
- django_cfg/apps/grpc/interceptors/errors.py +241 -0
- django_cfg/apps/grpc/interceptors/logging.py +270 -0
- django_cfg/apps/grpc/interceptors/metrics.py +306 -0
- django_cfg/apps/grpc/interceptors/request_logger.py +515 -0
- django_cfg/apps/grpc/management/__init__.py +1 -0
- django_cfg/apps/grpc/management/commands/__init__.py +0 -0
- django_cfg/apps/grpc/management/commands/rungrpc.py +302 -0
- django_cfg/apps/grpc/managers/__init__.py +10 -0
- django_cfg/apps/grpc/managers/grpc_request_log.py +310 -0
- django_cfg/apps/grpc/migrations/0001_initial.py +69 -0
- django_cfg/apps/grpc/migrations/0002_rename_django_cfg__service_4c4a8e_idx_django_cfg__service_584308_idx_and_more.py +38 -0
- django_cfg/apps/grpc/migrations/__init__.py +0 -0
- django_cfg/apps/grpc/models/__init__.py +9 -0
- django_cfg/apps/grpc/models/grpc_request_log.py +219 -0
- django_cfg/apps/grpc/serializers/__init__.py +23 -0
- django_cfg/apps/grpc/serializers/health.py +18 -0
- django_cfg/apps/grpc/serializers/requests.py +18 -0
- django_cfg/apps/grpc/serializers/services.py +50 -0
- django_cfg/apps/grpc/serializers/stats.py +22 -0
- django_cfg/apps/grpc/services/__init__.py +16 -0
- django_cfg/apps/grpc/services/base.py +375 -0
- django_cfg/apps/grpc/services/discovery.py +415 -0
- django_cfg/apps/grpc/urls.py +23 -0
- django_cfg/apps/grpc/utils/__init__.py +13 -0
- django_cfg/apps/grpc/utils/proto_gen.py +423 -0
- django_cfg/apps/grpc/views/__init__.py +9 -0
- django_cfg/apps/grpc/views/monitoring.py +497 -0
- django_cfg/apps/maintenance/admin/api_key_admin.py +7 -8
- django_cfg/apps/maintenance/admin/site_admin.py +5 -4
- django_cfg/apps/payments/admin/balance_admin.py +26 -36
- django_cfg/apps/payments/admin/payment_admin.py +65 -85
- django_cfg/apps/payments/admin/withdrawal_admin.py +65 -100
- django_cfg/apps/tasks/admin/task_log.py +20 -47
- django_cfg/apps/urls.py +7 -1
- django_cfg/config.py +106 -0
- django_cfg/core/base/config_model.py +6 -0
- django_cfg/core/builders/apps_builder.py +3 -0
- django_cfg/core/generation/integration_generators/grpc_generator.py +318 -0
- django_cfg/core/generation/orchestrator.py +10 -0
- django_cfg/models/api/grpc/__init__.py +59 -0
- django_cfg/models/api/grpc/config.py +364 -0
- django_cfg/modules/base.py +15 -0
- django_cfg/modules/django_admin/__init__.py +2 -0
- django_cfg/modules/django_admin/base/pydantic_admin.py +2 -2
- django_cfg/modules/django_admin/config/__init__.py +2 -0
- django_cfg/modules/django_admin/config/field_config.py +24 -0
- django_cfg/modules/django_admin/utils/__init__.py +41 -3
- django_cfg/modules/django_admin/utils/badges/__init__.py +13 -0
- django_cfg/modules/django_admin/utils/{badges.py → badges/status_badges.py} +3 -3
- django_cfg/modules/django_admin/utils/displays/__init__.py +13 -0
- django_cfg/modules/django_admin/utils/{displays.py → displays/data_displays.py} +2 -2
- django_cfg/modules/django_admin/utils/html/__init__.py +26 -0
- django_cfg/modules/django_admin/utils/html/badges.py +47 -0
- django_cfg/modules/django_admin/utils/html/base.py +167 -0
- django_cfg/modules/django_admin/utils/html/code.py +87 -0
- django_cfg/modules/django_admin/utils/html/composition.py +198 -0
- django_cfg/modules/django_admin/utils/html/formatting.py +231 -0
- django_cfg/modules/django_admin/utils/html/keyvalue.py +219 -0
- django_cfg/modules/django_admin/utils/html/markdown_integration.py +108 -0
- django_cfg/modules/django_admin/utils/html/progress.py +127 -0
- django_cfg/modules/django_admin/utils/html_builder.py +55 -408
- django_cfg/modules/django_admin/utils/markdown/__init__.py +21 -0
- django_cfg/modules/django_admin/widgets/registry.py +42 -0
- django_cfg/modules/django_unfold/navigation.py +28 -0
- django_cfg/pyproject.toml +3 -5
- django_cfg/registry/modules.py +6 -0
- {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/METADATA +10 -1
- {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/RECORD +83 -34
- django_cfg/modules/django_admin/utils/CODE_BLOCK_DOCS.md +0 -396
- /django_cfg/modules/django_admin/utils/{mermaid_plugin.py → markdown/mermaid_plugin.py} +0 -0
- /django_cfg/modules/django_admin/utils/{markdown_renderer.py → markdown/renderer.py} +0 -0
- {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.119.dist-info → django_cfg-1.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Generated by Django 5.2.7 on 2025-11-01 13:48
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("grpc", "0001_initial"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RenameIndex(
|
|
14
|
+
model_name="grpcrequestlog",
|
|
15
|
+
new_name="django_cfg__service_584308_idx",
|
|
16
|
+
old_name="django_cfg__service_4c4a8e_idx",
|
|
17
|
+
),
|
|
18
|
+
migrations.RenameIndex(
|
|
19
|
+
model_name="grpcrequestlog",
|
|
20
|
+
new_name="django_cfg__method__5e704d_idx",
|
|
21
|
+
old_name="django_cfg__method__8e1a7c_idx",
|
|
22
|
+
),
|
|
23
|
+
migrations.RenameIndex(
|
|
24
|
+
model_name="grpcrequestlog",
|
|
25
|
+
new_name="django_cfg__status_a564a8_idx",
|
|
26
|
+
old_name="django_cfg__status_f3d9a1_idx",
|
|
27
|
+
),
|
|
28
|
+
migrations.RenameIndex(
|
|
29
|
+
model_name="grpcrequestlog",
|
|
30
|
+
new_name="django_cfg__user_id_f2ada7_idx",
|
|
31
|
+
old_name="django_cfg__user_id_9c2b4f_idx",
|
|
32
|
+
),
|
|
33
|
+
migrations.RenameIndex(
|
|
34
|
+
model_name="grpcrequestlog",
|
|
35
|
+
new_name="django_cfg__grpc_st_fea09f_idx",
|
|
36
|
+
old_name="django_cfg__grpc_st_a7e5c2_idx",
|
|
37
|
+
),
|
|
38
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""
|
|
2
|
+
gRPC Request Log Model.
|
|
3
|
+
|
|
4
|
+
Django model for tracking gRPC requests and responses.
|
|
5
|
+
Provides observability for debugging and monitoring.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from django.conf import settings
|
|
9
|
+
from django.db import models
|
|
10
|
+
from django.utils import timezone
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class GRPCRequestLog(models.Model):
|
|
14
|
+
"""
|
|
15
|
+
Log of gRPC requests and responses.
|
|
16
|
+
|
|
17
|
+
Tracks all gRPC method calls with status, timing, and error tracking.
|
|
18
|
+
Provides observability for debugging and monitoring.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> log = GRPCRequestLog.objects.create(
|
|
22
|
+
... request_id="abc123",
|
|
23
|
+
... service_name="myapp.UserService",
|
|
24
|
+
... method_name="GetUser",
|
|
25
|
+
... )
|
|
26
|
+
>>> log.mark_success(duration_ms=125)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# Custom manager
|
|
30
|
+
from ..managers.grpc_request_log import GRPCRequestLogManager
|
|
31
|
+
|
|
32
|
+
objects: GRPCRequestLogManager = GRPCRequestLogManager()
|
|
33
|
+
|
|
34
|
+
class StatusChoices(models.TextChoices):
|
|
35
|
+
"""Status of gRPC request."""
|
|
36
|
+
|
|
37
|
+
PENDING = "pending", "Pending"
|
|
38
|
+
SUCCESS = "success", "Success"
|
|
39
|
+
ERROR = "error", "Error"
|
|
40
|
+
CANCELLED = "cancelled", "Cancelled"
|
|
41
|
+
TIMEOUT = "timeout", "Timeout"
|
|
42
|
+
|
|
43
|
+
# Identity
|
|
44
|
+
request_id = models.CharField(
|
|
45
|
+
max_length=100,
|
|
46
|
+
unique=True,
|
|
47
|
+
db_index=True,
|
|
48
|
+
help_text="Unique request identifier (UUID)",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# gRPC details
|
|
52
|
+
service_name = models.CharField(
|
|
53
|
+
max_length=200,
|
|
54
|
+
db_index=True,
|
|
55
|
+
help_text="gRPC service name (e.g., myapp.UserService)",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
method_name = models.CharField(
|
|
59
|
+
max_length=200,
|
|
60
|
+
db_index=True,
|
|
61
|
+
help_text="gRPC method name (e.g., GetUser)",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
full_method = models.CharField(
|
|
65
|
+
max_length=400,
|
|
66
|
+
db_index=True,
|
|
67
|
+
help_text="Full method path (e.g., /myapp.UserService/GetUser)",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Request/Response data
|
|
71
|
+
request_size = models.IntegerField(
|
|
72
|
+
null=True,
|
|
73
|
+
blank=True,
|
|
74
|
+
help_text="Request size in bytes",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
response_size = models.IntegerField(
|
|
78
|
+
null=True,
|
|
79
|
+
blank=True,
|
|
80
|
+
help_text="Response size in bytes",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
request_data = models.JSONField(
|
|
84
|
+
null=True,
|
|
85
|
+
blank=True,
|
|
86
|
+
help_text="Request data (if logged)",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
response_data = models.JSONField(
|
|
90
|
+
null=True,
|
|
91
|
+
blank=True,
|
|
92
|
+
help_text="Response data (if logged)",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Status tracking
|
|
96
|
+
status = models.CharField(
|
|
97
|
+
max_length=20,
|
|
98
|
+
choices=StatusChoices.choices,
|
|
99
|
+
default=StatusChoices.PENDING,
|
|
100
|
+
db_index=True,
|
|
101
|
+
help_text="Current status of request",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
grpc_status_code = models.CharField(
|
|
105
|
+
max_length=50,
|
|
106
|
+
null=True,
|
|
107
|
+
blank=True,
|
|
108
|
+
db_index=True,
|
|
109
|
+
help_text="gRPC status code (OK, CANCELLED, INVALID_ARGUMENT, etc.)",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
error_message = models.TextField(
|
|
113
|
+
null=True,
|
|
114
|
+
blank=True,
|
|
115
|
+
help_text="Error message if failed",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
error_details = models.JSONField(
|
|
119
|
+
null=True,
|
|
120
|
+
blank=True,
|
|
121
|
+
help_text="Additional error details",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Performance
|
|
125
|
+
duration_ms = models.IntegerField(
|
|
126
|
+
null=True,
|
|
127
|
+
blank=True,
|
|
128
|
+
help_text="Total duration in milliseconds",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# User context
|
|
132
|
+
user = models.ForeignKey(
|
|
133
|
+
settings.AUTH_USER_MODEL,
|
|
134
|
+
on_delete=models.SET_NULL,
|
|
135
|
+
null=True,
|
|
136
|
+
blank=True,
|
|
137
|
+
related_name="grpc_request_logs",
|
|
138
|
+
help_text="Authenticated user (if applicable)",
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
is_authenticated = models.BooleanField(
|
|
142
|
+
default=False,
|
|
143
|
+
db_index=True,
|
|
144
|
+
help_text="Whether request was authenticated",
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Client metadata
|
|
148
|
+
client_ip = models.GenericIPAddressField(
|
|
149
|
+
null=True,
|
|
150
|
+
blank=True,
|
|
151
|
+
help_text="Client IP address",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
user_agent = models.TextField(
|
|
155
|
+
null=True,
|
|
156
|
+
blank=True,
|
|
157
|
+
help_text="User agent from metadata",
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
peer = models.CharField(
|
|
161
|
+
max_length=200,
|
|
162
|
+
null=True,
|
|
163
|
+
blank=True,
|
|
164
|
+
help_text="gRPC peer information",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Timestamps
|
|
168
|
+
created_at = models.DateTimeField(
|
|
169
|
+
auto_now_add=True,
|
|
170
|
+
db_index=True,
|
|
171
|
+
help_text="When request was received",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
completed_at = models.DateTimeField(
|
|
175
|
+
null=True,
|
|
176
|
+
blank=True,
|
|
177
|
+
db_index=True,
|
|
178
|
+
help_text="When request completed (success/error)",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
class Meta:
|
|
182
|
+
db_table = "django_cfg_grpc_request_log"
|
|
183
|
+
ordering = ["-created_at"]
|
|
184
|
+
indexes = [
|
|
185
|
+
models.Index(fields=["service_name", "-created_at"]),
|
|
186
|
+
models.Index(fields=["method_name", "-created_at"]),
|
|
187
|
+
models.Index(fields=["status", "-created_at"]),
|
|
188
|
+
models.Index(fields=["user", "-created_at"]),
|
|
189
|
+
models.Index(fields=["grpc_status_code", "-created_at"]),
|
|
190
|
+
]
|
|
191
|
+
verbose_name = "gRPC Request Log"
|
|
192
|
+
verbose_name_plural = "gRPC Request Logs"
|
|
193
|
+
|
|
194
|
+
def __str__(self) -> str:
|
|
195
|
+
"""String representation."""
|
|
196
|
+
return f"{self.full_method} ({self.request_id[:8]}...) - {self.status}"
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def is_completed(self) -> bool:
|
|
200
|
+
"""Check if request is completed (any terminal status)."""
|
|
201
|
+
return self.status in [
|
|
202
|
+
self.StatusChoices.SUCCESS,
|
|
203
|
+
self.StatusChoices.ERROR,
|
|
204
|
+
self.StatusChoices.CANCELLED,
|
|
205
|
+
self.StatusChoices.TIMEOUT,
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def is_successful(self) -> bool:
|
|
210
|
+
"""Check if request was successful."""
|
|
211
|
+
return self.status == self.StatusChoices.SUCCESS
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def success_rate(self) -> float:
|
|
215
|
+
"""Calculate success rate (for compatibility with stats)."""
|
|
216
|
+
return 1.0 if self.is_successful else 0.0
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
__all__ = ["GRPCRequestLog"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic serializers for gRPC monitoring API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .health import HealthCheckSerializer
|
|
6
|
+
from .requests import RecentRequestsSerializer
|
|
7
|
+
from .services import (
|
|
8
|
+
MethodListSerializer,
|
|
9
|
+
MethodStatsSerializer,
|
|
10
|
+
ServiceListSerializer,
|
|
11
|
+
ServiceStatsSerializer,
|
|
12
|
+
)
|
|
13
|
+
from .stats import OverviewStatsSerializer
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"HealthCheckSerializer",
|
|
17
|
+
"OverviewStatsSerializer",
|
|
18
|
+
"RecentRequestsSerializer",
|
|
19
|
+
"ServiceStatsSerializer",
|
|
20
|
+
"ServiceListSerializer",
|
|
21
|
+
"MethodStatsSerializer",
|
|
22
|
+
"MethodListSerializer",
|
|
23
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Health check serializer for gRPC monitoring API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HealthCheckSerializer(BaseModel):
|
|
9
|
+
"""Health check response."""
|
|
10
|
+
|
|
11
|
+
status: str = Field(description="Health status: healthy or unhealthy")
|
|
12
|
+
server_host: str = Field(description="Configured gRPC server host")
|
|
13
|
+
server_port: int = Field(description="Configured gRPC server port")
|
|
14
|
+
enabled: bool = Field(description="Whether gRPC is enabled")
|
|
15
|
+
timestamp: str = Field(description="Current timestamp")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["HealthCheckSerializer"]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Requests serializers for gRPC monitoring API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RecentRequestsSerializer(BaseModel):
|
|
9
|
+
"""Recent gRPC requests list."""
|
|
10
|
+
|
|
11
|
+
requests: list[dict] = Field(description="List of recent requests")
|
|
12
|
+
count: int = Field(description="Number of requests returned")
|
|
13
|
+
total_available: int = Field(description="Total requests available")
|
|
14
|
+
offset: int = Field(default=0, description="Current offset for pagination")
|
|
15
|
+
has_more: bool = Field(default=False, description="Whether more results are available")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["RecentRequestsSerializer"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Services serializers for gRPC monitoring API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ServiceStatsSerializer(BaseModel):
|
|
9
|
+
"""Statistics for a single gRPC service."""
|
|
10
|
+
|
|
11
|
+
service_name: str = Field(description="Service name")
|
|
12
|
+
total: int = Field(description="Total requests")
|
|
13
|
+
successful: int = Field(description="Successful requests")
|
|
14
|
+
errors: int = Field(description="Error requests")
|
|
15
|
+
avg_duration_ms: float = Field(description="Average duration")
|
|
16
|
+
last_activity_at: str | None = Field(description="Last activity timestamp")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ServiceListSerializer(BaseModel):
|
|
20
|
+
"""List of gRPC services with statistics."""
|
|
21
|
+
|
|
22
|
+
services: list[ServiceStatsSerializer] = Field(description="Service statistics")
|
|
23
|
+
total_services: int = Field(description="Total number of services")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MethodStatsSerializer(BaseModel):
|
|
27
|
+
"""Statistics for a single gRPC method."""
|
|
28
|
+
|
|
29
|
+
method_name: str = Field(description="Method name")
|
|
30
|
+
service_name: str = Field(description="Service name")
|
|
31
|
+
total: int = Field(description="Total requests")
|
|
32
|
+
successful: int = Field(description="Successful requests")
|
|
33
|
+
errors: int = Field(description="Error requests")
|
|
34
|
+
avg_duration_ms: float = Field(description="Average duration")
|
|
35
|
+
last_activity_at: str | None = Field(description="Last activity timestamp")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MethodListSerializer(BaseModel):
|
|
39
|
+
"""List of gRPC methods with statistics."""
|
|
40
|
+
|
|
41
|
+
methods: list[MethodStatsSerializer] = Field(description="Method statistics")
|
|
42
|
+
total_methods: int = Field(description="Total number of methods")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
"ServiceStatsSerializer",
|
|
47
|
+
"ServiceListSerializer",
|
|
48
|
+
"MethodStatsSerializer",
|
|
49
|
+
"MethodListSerializer",
|
|
50
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Statistics serializers for gRPC monitoring API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class OverviewStatsSerializer(BaseModel):
|
|
9
|
+
"""Overview statistics for gRPC requests."""
|
|
10
|
+
|
|
11
|
+
total: int = Field(description="Total requests in period")
|
|
12
|
+
successful: int = Field(description="Successful requests")
|
|
13
|
+
errors: int = Field(description="Error requests")
|
|
14
|
+
cancelled: int = Field(description="Cancelled requests")
|
|
15
|
+
timeout: int = Field(description="Timeout requests")
|
|
16
|
+
success_rate: float = Field(description="Success rate percentage")
|
|
17
|
+
avg_duration_ms: float = Field(description="Average duration in milliseconds")
|
|
18
|
+
p95_duration_ms: float | None = Field(description="95th percentile duration in milliseconds")
|
|
19
|
+
period_hours: int = Field(description="Statistics period in hours")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__ = ["OverviewStatsSerializer"]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
gRPC services utilities.
|
|
3
|
+
|
|
4
|
+
Provides service discovery and base classes for gRPC services.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .base import AuthRequiredService, BaseService, ReadOnlyService
|
|
8
|
+
from .discovery import ServiceDiscovery, discover_and_register_services
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"BaseService",
|
|
12
|
+
"ReadOnlyService",
|
|
13
|
+
"AuthRequiredService",
|
|
14
|
+
"ServiceDiscovery",
|
|
15
|
+
"discover_and_register_services",
|
|
16
|
+
]
|