varanus 0.1.0.dev2__tar.gz → 0.1.0.dev3__tar.gz
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.
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/PKG-INFO +1 -1
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/pyproject.toml +1 -1
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/apps.py +1 -1
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/client.py +33 -30
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/context.py +11 -11
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/middleware.py +6 -6
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/transport/base.py +1 -1
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/transport/database.py +4 -1
- varanus-0.1.0.dev3/src/varanus/client/transport/http.py +83 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/search/base.py +1 -3
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/views/api.py +20 -12
- varanus-0.1.0.dev2/src/varanus/client/transport/http.py +0 -37
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/README.md +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/loggers.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/client/transport/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/events.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/__main__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/admin.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/apps.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/asgi.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/context_processors.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/management/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/management/commands/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/management/commands/migrateall.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/middleware.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/migrations/0001_initial.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/migrations/0002_context_node_error_node_log_node_metric_node_and_more.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/migrations/0003_alter_log_level.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/migrations/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/models.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/router.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/search/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/search/date.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/search/facet.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/settings.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/static/css/varanus.css +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/static/js/varanus.js +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/base.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/dashboard.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/registration/login.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/search/daterange.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/search/multifacet.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/base.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/environment_nodes.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/error.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/log.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/metric.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/node.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/node_environments.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/query.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/request.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/errors.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/logs.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/metrics.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/overview.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/queries.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/requests.html +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templatetags/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templatetags/varanus.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/urls.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/views/__init__.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/views/base.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/views/dashboard.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/views/site.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/wsgi.py +0 -0
- {varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/utils.py +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import platform
|
|
2
2
|
from importlib.metadata import distributions
|
|
3
|
-
from typing import Union
|
|
4
3
|
from urllib.parse import urlsplit
|
|
5
4
|
|
|
6
5
|
from varanus.events import Context, NodeInfo
|
|
@@ -20,14 +19,14 @@ def install_query_logger(logger):
|
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
class VaranusClient:
|
|
23
|
-
environment: str
|
|
22
|
+
environment: str
|
|
24
23
|
transport: BaseTransport
|
|
25
24
|
|
|
26
25
|
request_attr: str
|
|
27
26
|
logger_name: str
|
|
28
27
|
tags: dict
|
|
29
28
|
|
|
30
|
-
include_headers:
|
|
29
|
+
include_headers: list | bool | None
|
|
31
30
|
exclude_headers: list | None
|
|
32
31
|
sensitive_headers = set(
|
|
33
32
|
[
|
|
@@ -38,9 +37,8 @@ class VaranusClient:
|
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
scheme_transports = {
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"https": "varanus.client.transport.http.HttpTransport",
|
|
40
|
+
"http": "varanus.client.transport.http.ThreadedHttpTransport",
|
|
41
|
+
"https": "varanus.client.transport.http.ThreadedHttpTransport",
|
|
44
42
|
"db": "varanus.client.transport.database.ModelTransport",
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -49,29 +47,38 @@ class VaranusClient:
|
|
|
49
47
|
|
|
50
48
|
def setup(
|
|
51
49
|
self,
|
|
52
|
-
dsn,
|
|
53
|
-
|
|
54
|
-
environment=
|
|
55
|
-
transport_class=None,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
dsn: str,
|
|
51
|
+
node: str | None = None,
|
|
52
|
+
environment: str = "",
|
|
53
|
+
transport_class: str | type[BaseTransport] | None = None,
|
|
54
|
+
request_attr: str = "varanus",
|
|
55
|
+
logger_name: str = "varanus.request",
|
|
56
|
+
tags: dict | None = None,
|
|
57
|
+
include_headers: list | bool | None = None,
|
|
58
|
+
exclude_headers: list | None = None,
|
|
60
59
|
log_queries: bool | int = False,
|
|
61
|
-
log_query_params=False,
|
|
62
|
-
query_metrics=False,
|
|
63
|
-
send_all=False,
|
|
64
|
-
install=None,
|
|
60
|
+
log_query_params: bool = False,
|
|
61
|
+
query_metrics: bool | str = False,
|
|
62
|
+
send_all: bool = False,
|
|
63
|
+
install: list | None = None,
|
|
65
64
|
):
|
|
66
65
|
url = urlsplit(dsn)
|
|
67
66
|
self.environment = environment
|
|
67
|
+
self.node = node or platform.node()
|
|
68
68
|
if transport_class is None:
|
|
69
|
-
|
|
70
|
-
if transport_class is None:
|
|
69
|
+
if url.scheme not in self.scheme_transports:
|
|
71
70
|
raise ValueError(f"No transport class found for `{url.scheme}`")
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
resolved_class = import_string(self.scheme_transports[url.scheme])
|
|
72
|
+
elif isinstance(transport_class, str):
|
|
73
|
+
resolved_class = import_string(transport_class)
|
|
74
|
+
else:
|
|
75
|
+
resolved_class = transport_class
|
|
76
|
+
if not issubclass(resolved_class, BaseTransport):
|
|
77
|
+
raise ValueError(
|
|
78
|
+
f"Transport class `{transport_class}` must be a subclass of"
|
|
79
|
+
"BaseTransport."
|
|
80
|
+
)
|
|
81
|
+
self.transport = resolved_class(url, self.environment, self.node)
|
|
75
82
|
self.request_attr = request_attr
|
|
76
83
|
self.logger_name = logger_name
|
|
77
84
|
self.tags = tags or {}
|
|
@@ -98,10 +105,6 @@ class VaranusClient:
|
|
|
98
105
|
self.send_all = send_all
|
|
99
106
|
self.configured = True
|
|
100
107
|
if install:
|
|
101
|
-
if not isinstance(install, list):
|
|
102
|
-
raise TypeError(
|
|
103
|
-
"The varanus middleware can only be automatically installed into a list."
|
|
104
|
-
)
|
|
105
108
|
if "django.contrib.auth.middleware.AuthenticationMiddleware" in install:
|
|
106
109
|
idx = install.index(
|
|
107
110
|
"django.contrib.auth.middleware.AuthenticationMiddleware"
|
|
@@ -121,14 +124,14 @@ class VaranusClient:
|
|
|
121
124
|
def ping(self):
|
|
122
125
|
self.transport.ping(
|
|
123
126
|
NodeInfo(
|
|
124
|
-
name=
|
|
127
|
+
name=self.node,
|
|
125
128
|
platform=platform.platform(),
|
|
126
129
|
python_version=platform.python_version(),
|
|
127
130
|
packages={d.name: d.version for d in distributions()},
|
|
128
131
|
)
|
|
129
132
|
)
|
|
130
133
|
|
|
131
|
-
def log(self, level, message, *args, **kwargs):
|
|
134
|
+
def log(self, level: int, message: str, *args, **kwargs):
|
|
132
135
|
if ctx := current_context.get():
|
|
133
136
|
kwargs.setdefault("stacklevel", 2)
|
|
134
137
|
ctx.log(level, message, *args, **kwargs)
|
|
@@ -137,7 +140,7 @@ class VaranusClient:
|
|
|
137
140
|
if ctx := current_context.get():
|
|
138
141
|
ctx.raw_exception(exception, tags=tags)
|
|
139
142
|
|
|
140
|
-
def metric(self, name, value: float = 0.0, tags: dict | None = None):
|
|
143
|
+
def metric(self, name: str, value: float = 0.0, tags: dict | None = None):
|
|
141
144
|
if ctx := current_context.get():
|
|
142
145
|
ctx.metric(name, value, tags=tags)
|
|
143
146
|
|
|
@@ -78,11 +78,11 @@ class VaranusContext:
|
|
|
78
78
|
|
|
79
79
|
def log(
|
|
80
80
|
self,
|
|
81
|
-
level,
|
|
82
|
-
message,
|
|
81
|
+
level: int,
|
|
82
|
+
message: str,
|
|
83
83
|
*args,
|
|
84
84
|
exc_info=None,
|
|
85
|
-
stacklevel=1,
|
|
85
|
+
stacklevel: int = 1,
|
|
86
86
|
tags: dict | None = None,
|
|
87
87
|
**kwargs,
|
|
88
88
|
):
|
|
@@ -99,27 +99,27 @@ class VaranusContext:
|
|
|
99
99
|
)
|
|
100
100
|
)
|
|
101
101
|
|
|
102
|
-
def debug(self, message, *args, **kwargs):
|
|
102
|
+
def debug(self, message: str, *args, **kwargs):
|
|
103
103
|
kwargs.setdefault("stacklevel", 2)
|
|
104
104
|
self.log(logging.DEBUG, message, *args, **kwargs)
|
|
105
105
|
|
|
106
|
-
def info(self, message, *args, **kwargs):
|
|
106
|
+
def info(self, message: str, *args, **kwargs):
|
|
107
107
|
kwargs.setdefault("stacklevel", 2)
|
|
108
108
|
self.log(logging.INFO, message, *args, **kwargs)
|
|
109
109
|
|
|
110
|
-
def warning(self, message, *args, **kwargs):
|
|
110
|
+
def warning(self, message: str, *args, **kwargs):
|
|
111
111
|
kwargs.setdefault("stacklevel", 2)
|
|
112
112
|
self.log(logging.WARNING, message, *args, **kwargs)
|
|
113
113
|
|
|
114
|
-
def error(self, message, *args, **kwargs):
|
|
114
|
+
def error(self, message: str, *args, **kwargs):
|
|
115
115
|
kwargs.setdefault("stacklevel", 2)
|
|
116
116
|
self.log(logging.ERROR, message, *args, **kwargs)
|
|
117
117
|
|
|
118
|
-
def critical(self, message, *args, **kwargs):
|
|
118
|
+
def critical(self, message: str, *args, **kwargs):
|
|
119
119
|
kwargs.setdefault("stacklevel", 2)
|
|
120
120
|
self.log(logging.CRITICAL, message, *args, **kwargs)
|
|
121
121
|
|
|
122
|
-
def exception(self, message, *args, **kwargs):
|
|
122
|
+
def exception(self, message: str, *args, **kwargs):
|
|
123
123
|
kwargs.setdefault("stacklevel", 2)
|
|
124
124
|
kwargs.setdefault("exc_info", sys.exc_info())
|
|
125
125
|
self.log(logging.ERROR, message, *args, **kwargs)
|
|
@@ -128,12 +128,12 @@ class VaranusContext:
|
|
|
128
128
|
if err := Error.from_exception(exception, tags=tags):
|
|
129
129
|
self.errors.append(err)
|
|
130
130
|
|
|
131
|
-
def context(self, name="", tags: dict | None = None):
|
|
131
|
+
def context(self, name: str = "", tags: dict | None = None):
|
|
132
132
|
ctx = VaranusContext(self.client, name, tags)
|
|
133
133
|
self.subcontexts.append(ctx)
|
|
134
134
|
return ctx
|
|
135
135
|
|
|
136
|
-
def metric(self, name, value: float = 0.0, tags: dict | None = None):
|
|
136
|
+
def metric(self, name: str, value: float = 0.0, tags: dict | None = None):
|
|
137
137
|
if name not in self.metrics:
|
|
138
138
|
self.metrics[name] = Metric(name=name, tags=tags or {})
|
|
139
139
|
self.metrics[name].update(value)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import ipaddress
|
|
2
2
|
|
|
3
3
|
from django.core.exceptions import MiddlewareNotUsed
|
|
4
4
|
from django.http import HttpRequest, HttpResponse
|
|
@@ -6,8 +6,6 @@ from django.http import HttpRequest, HttpResponse
|
|
|
6
6
|
from ..events import Request
|
|
7
7
|
from .client import client
|
|
8
8
|
|
|
9
|
-
IP_REGEX = re.compile(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
def get_ip(request: HttpRequest):
|
|
13
11
|
ip_address = request.META.get("HTTP_X_FORWARDED_FOR", "").strip()
|
|
@@ -15,9 +13,11 @@ def get_ip(request: HttpRequest):
|
|
|
15
13
|
ip_address = ip_address.split(",")[0].strip()
|
|
16
14
|
if not ip_address:
|
|
17
15
|
ip_address = request.META.get("REMOTE_ADDR", "127.0.0.1").strip()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
try:
|
|
17
|
+
# Validate and normalize the IP address.
|
|
18
|
+
return str(ipaddress.ip_address(ip_address))
|
|
19
|
+
except ValueError:
|
|
20
|
+
return ""
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def request_headers(request: HttpRequest):
|
|
@@ -10,8 +10,9 @@ from .base import BaseTransport
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class ModelTransport(BaseTransport):
|
|
13
|
-
def __init__(self, url: SplitResult, environment: str):
|
|
13
|
+
def __init__(self, url: SplitResult, environment: str, node: str):
|
|
14
14
|
self.environment = environment
|
|
15
|
+
self.node = node
|
|
15
16
|
|
|
16
17
|
def ping(self, info: events.NodeInfo):
|
|
17
18
|
site = models.Site.objects.get()
|
|
@@ -20,9 +21,11 @@ class ModelTransport(BaseTransport):
|
|
|
20
21
|
@transaction.atomic
|
|
21
22
|
def send(self, event: events.Context):
|
|
22
23
|
site = models.Site.objects.get()
|
|
24
|
+
node = site.nodes.get(name=self.node, environment=self.environment)
|
|
23
25
|
models.Context.from_event(
|
|
24
26
|
event,
|
|
25
27
|
event_id=uuid.uuid4(),
|
|
26
28
|
site=site,
|
|
27
29
|
environment=self.environment,
|
|
30
|
+
node=node,
|
|
28
31
|
)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import queue
|
|
3
|
+
import threading
|
|
4
|
+
import time
|
|
5
|
+
from typing import Any
|
|
6
|
+
from urllib.parse import SplitResult, parse_qs
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
import msgspec
|
|
10
|
+
|
|
11
|
+
from varanus import events
|
|
12
|
+
|
|
13
|
+
from .base import BaseTransport
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class HttpTransport(BaseTransport):
|
|
19
|
+
def __init__(self, url: SplitResult, environment: str, node: str):
|
|
20
|
+
path = url.path.rstrip("/")
|
|
21
|
+
self.ping_url = f"{url.scheme}://{url.netloc}{path}/api/ping/"
|
|
22
|
+
self.event_url = f"{url.scheme}://{url.netloc}{path}/api/ingest/"
|
|
23
|
+
self.options = parse_qs(url.query, keep_blank_values=True)
|
|
24
|
+
timeout = 1.0
|
|
25
|
+
if "timeout" in self.options:
|
|
26
|
+
timeout = float(self.options["timeout"][0])
|
|
27
|
+
self.client = httpx.Client(
|
|
28
|
+
headers={
|
|
29
|
+
"X-Varanus-Key": url.username or "",
|
|
30
|
+
"X-Varanus-Environment": environment,
|
|
31
|
+
"X-Varanus-Node": node,
|
|
32
|
+
},
|
|
33
|
+
timeout=timeout,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def request(self, url: str, obj: Any):
|
|
37
|
+
try:
|
|
38
|
+
self.client.post(url, content=msgspec.json.encode(obj))
|
|
39
|
+
except Exception:
|
|
40
|
+
logger.exception("error sending to %s", url)
|
|
41
|
+
|
|
42
|
+
def ping(self, info: events.NodeInfo):
|
|
43
|
+
self.request(self.ping_url, info)
|
|
44
|
+
|
|
45
|
+
def send(self, event: events.Context):
|
|
46
|
+
self.request(self.event_url, [event])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def sender(pending: queue.SimpleQueue, client: httpx.Client, url: str, rate: float):
|
|
50
|
+
while True:
|
|
51
|
+
start = time.time()
|
|
52
|
+
events = []
|
|
53
|
+
while True:
|
|
54
|
+
try:
|
|
55
|
+
events.append(pending.get_nowait())
|
|
56
|
+
except queue.Empty:
|
|
57
|
+
break
|
|
58
|
+
if len(events) >= 100:
|
|
59
|
+
break
|
|
60
|
+
if events:
|
|
61
|
+
try:
|
|
62
|
+
client.post(url, content=msgspec.json.encode(events))
|
|
63
|
+
except Exception:
|
|
64
|
+
logger.exception("error sending to %s", url)
|
|
65
|
+
elapsed = time.time() - start
|
|
66
|
+
time.sleep(max(rate - elapsed, 1.0))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ThreadedHttpTransport(HttpTransport):
|
|
70
|
+
def __init__(self, url: SplitResult, environment: str, node: str):
|
|
71
|
+
super().__init__(url, environment, node)
|
|
72
|
+
self.pending = queue.SimpleQueue()
|
|
73
|
+
rate = 3.0
|
|
74
|
+
if "rate" in self.options:
|
|
75
|
+
rate = float(self.options["rate"][0])
|
|
76
|
+
threading.Thread(
|
|
77
|
+
target=sender,
|
|
78
|
+
args=(self.pending, self.client, self.event_url, rate),
|
|
79
|
+
daemon=True,
|
|
80
|
+
).start()
|
|
81
|
+
|
|
82
|
+
def send(self, event: events.Context):
|
|
83
|
+
self.pending.put(event)
|
|
@@ -46,7 +46,6 @@ class SearchField:
|
|
|
46
46
|
self.order = order
|
|
47
47
|
|
|
48
48
|
def __set_name__(self, owner, name: str):
|
|
49
|
-
# print("__set_name__", owner, name)
|
|
50
49
|
assert issubclass(owner, Search)
|
|
51
50
|
self.name = name
|
|
52
51
|
self.prefix = f"{name}_"
|
|
@@ -60,7 +59,6 @@ class SearchField:
|
|
|
60
59
|
owner._fields.append(self)
|
|
61
60
|
|
|
62
61
|
def __get__(self, instance: "Search", owner=None) -> StringValues | Self:
|
|
63
|
-
# print("__get__", instance, owner)
|
|
64
62
|
if owner is None:
|
|
65
63
|
return self
|
|
66
64
|
return {
|
|
@@ -70,7 +68,7 @@ class SearchField:
|
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
def __set__(self, instance, value):
|
|
73
|
-
|
|
71
|
+
raise AttributeError(f"`{self.name}` is read-only")
|
|
74
72
|
|
|
75
73
|
def apply(self, queryset: QuerySet, field_data: StringValues) -> QuerySet:
|
|
76
74
|
raise NotImplementedError()
|
|
@@ -22,6 +22,7 @@ class APIView(View):
|
|
|
22
22
|
self.key = SiteKey.objects.select_related("site").get(
|
|
23
23
|
access_key=request.META.get("HTTP_X_VARANUS_KEY", ""), active=True
|
|
24
24
|
)
|
|
25
|
+
self.node = request.META.get("HTTP_X_VARANUS_NODE", "")
|
|
25
26
|
self.environment = request.META.get("HTTP_X_VARANUS_ENVIRONMENT", "")
|
|
26
27
|
self.site = self.key.site
|
|
27
28
|
with self.site.activated():
|
|
@@ -32,7 +33,6 @@ class APIView(View):
|
|
|
32
33
|
except SiteKey.DoesNotExist:
|
|
33
34
|
return JsonResponse({"error": "Invalid site key."}, status=401)
|
|
34
35
|
except Exception as e:
|
|
35
|
-
raise e
|
|
36
36
|
return JsonResponse({"error": str(e)}, status=400)
|
|
37
37
|
|
|
38
38
|
|
|
@@ -45,17 +45,25 @@ class NodePingView(APIView):
|
|
|
45
45
|
|
|
46
46
|
class IngestView(APIView):
|
|
47
47
|
def post(self, request, *args, **kwargs):
|
|
48
|
-
|
|
48
|
+
try:
|
|
49
|
+
# Try to decode a list of events first.
|
|
50
|
+
event_list = msgspec.json.decode(request.body, type=list[events.Context])
|
|
51
|
+
except msgspec.ValidationError:
|
|
52
|
+
# Fall back to single event decoding.
|
|
53
|
+
event_list = [msgspec.json.decode(request.body, type=events.Context)]
|
|
49
54
|
# TODO: cache these
|
|
50
55
|
node = self.site.nodes.filter(
|
|
51
|
-
name=
|
|
52
|
-
environment=self.environment,
|
|
53
|
-
).first()
|
|
54
|
-
context = Context.from_event(
|
|
55
|
-
event,
|
|
56
|
-
event_id=uuid.uuid4(),
|
|
57
|
-
site=self.site,
|
|
56
|
+
name=self.node,
|
|
58
57
|
environment=self.environment,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
).get()
|
|
59
|
+
created_ids = []
|
|
60
|
+
for event in event_list:
|
|
61
|
+
context = Context.from_event(
|
|
62
|
+
event,
|
|
63
|
+
event_id=uuid.uuid4(),
|
|
64
|
+
site=self.site,
|
|
65
|
+
environment=self.environment,
|
|
66
|
+
node=node,
|
|
67
|
+
)
|
|
68
|
+
created_ids.append(context.event_id)
|
|
69
|
+
return {"created": created_ids}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import platform
|
|
2
|
-
from typing import Any
|
|
3
|
-
from urllib.parse import SplitResult
|
|
4
|
-
|
|
5
|
-
import httpx
|
|
6
|
-
import msgspec
|
|
7
|
-
|
|
8
|
-
from varanus import events
|
|
9
|
-
|
|
10
|
-
from .base import BaseTransport
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class HttpTransport(BaseTransport):
|
|
14
|
-
def __init__(self, url: SplitResult, environment: str):
|
|
15
|
-
path = url.path.rstrip("/")
|
|
16
|
-
self.ping_url = f"{url.scheme}://{url.netloc}{path}/api/ping/"
|
|
17
|
-
self.event_url = f"{url.scheme}://{url.netloc}{path}/api/ingest/"
|
|
18
|
-
self.client = httpx.Client(
|
|
19
|
-
headers={
|
|
20
|
-
"X-Varanus-Key": url.username or "",
|
|
21
|
-
"X-Varanus-Environment": environment or "",
|
|
22
|
-
"X-Varanus-Node": platform.node(),
|
|
23
|
-
},
|
|
24
|
-
timeout=1.0,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
def request(self, url: str, obj: Any):
|
|
28
|
-
try:
|
|
29
|
-
self.client.post(url, content=msgspec.json.encode(obj))
|
|
30
|
-
except Exception as ex:
|
|
31
|
-
print(f"error sending to {url}: {ex}")
|
|
32
|
-
|
|
33
|
-
def ping(self, info: events.NodeInfo):
|
|
34
|
-
self.request(self.ping_url, info)
|
|
35
|
-
|
|
36
|
-
def send(self, event: events.Context):
|
|
37
|
-
self.request(self.event_url, event)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/management/commands/__init__.py
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/management/commands/migrateall.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/migrations/0003_alter_log_level.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/registration/login.html
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/search/daterange.html
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/search/multifacet.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/error.html
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/log.html
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/metric.html
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/node.html
RENAMED
|
File without changes
|
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/query.html
RENAMED
|
File without changes
|
{varanus-0.1.0.dev2 → varanus-0.1.0.dev3}/src/varanus/server/templates/site/details/request.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|