Skip to content

Commit 06d7583

Browse files
feat: Add pilot logging
1 parent 21fa119 commit 06d7583

File tree

20 files changed

+711
-77
lines changed

20 files changed

+711
-77
lines changed

diracx-core/src/diracx/core/models.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class VectorSearchOperator(StrEnum):
3434
class ScalarSearchSpec(TypedDict):
3535
parameter: str
3636
operator: ScalarSearchOperator
37-
value: str | int | datetime
37+
value: str | int | datetime | bytes
3838

3939

4040
class VectorSearchSpec(TypedDict):
@@ -392,3 +392,10 @@ class VacuumPilotAuth(PilotAuthCredentials):
392392
grid_type: str
393393
grid_site: str
394394
status: str
395+
396+
397+
class LogLine(BaseModel):
398+
timestamp: str
399+
severity: str
400+
message: str
401+
scope: str

diracx-db/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ TaskQueueDB = "diracx.db.sql:TaskQueueDB"
3434

3535
[project.entry-points."diracx.dbs.os"]
3636
JobParametersDB = "diracx.db.os:JobParametersDB"
37+
PilotLogsDB = "diracx.db.os:PilotLogsDB"
3738

3839
[build-system]
3940
requires = ["hatchling", "hatch-vcs"]
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3-
__all__ = ("JobParametersDB",)
3+
__all__ = ("JobParametersDB", "PilotLogsDB")
44

55
from .job_parameters import JobParametersDB
6+
from .pilot_logs import PilotLogsDB
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from __future__ import annotations
2+
3+
from diracx.db.os.utils import BaseOSDB
4+
5+
6+
class PilotLogsDB(BaseOSDB):
7+
fields = {
8+
"PilotStamp": {"type": "keyword"},
9+
"PilotID": {"type": "long"},
10+
"Severity": {"type": "keyword"},
11+
"Message": {"type": "text"},
12+
"VO": {"type": "keyword"},
13+
"TimeStamp": {"type": "date_nanos"},
14+
"Scope": {"type": "keyword"},
15+
}
16+
index_prefix = "pilot_logs"
17+
18+
def index_name(self, vo: str, doc_id: int) -> str:
19+
split = int(int(doc_id) // 1e6)
20+
# We split docs into smaller one (grouped by 1 million pilot)
21+
# Ex: pilot_logs_dteam_1030m
22+
return f"{self.index_prefix}_{vo.lower()}_{split}m"

diracx-db/src/diracx/db/os/utils.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from opensearchpy.helpers import async_bulk
4+
35
__all__ = ("BaseOSDB",)
46

57
import contextlib
@@ -197,13 +199,35 @@ async def upsert(self, vo: str, doc_id: int, document: Any) -> None:
197199
response,
198200
)
199201

202+
async def bulk_insert(self, index_name: str, docs: list[dict[str, Any]]) -> None:
203+
"""Bulk inserting to database."""
204+
n_inserted, failed = await async_bulk(
205+
self.client, actions=[doc | {"_index": index_name} for doc in docs]
206+
)
207+
logger.info("Inserted %d documents to %s", n_inserted, index_name)
208+
209+
if failed:
210+
logger.error("Fail to insert %d documents to %s", failed, index_name)
211+
200212
async def search(
201-
self, parameters, search, sorts, *, per_page: int = 100, page: int | None = None
202-
) -> list[dict[str, Any]]:
213+
self,
214+
parameters,
215+
search,
216+
sorts,
217+
*,
218+
per_page: int = 10000,
219+
page: int | None = None,
220+
) -> tuple[int, list[dict[str, Any]]]:
203221
"""Search the database for matching results.
204222
205223
See the DiracX search API documentation for details.
206224
"""
225+
if page:
226+
if page < 1:
227+
raise InvalidQueryError("Page must be a positive integer")
228+
if per_page < 1:
229+
raise InvalidQueryError("Per page must be a positive integer")
230+
207231
body = {}
208232
if parameters:
209233
body["_source"] = parameters
@@ -213,7 +237,12 @@ async def search(
213237
for sort in sorts:
214238
field_name = sort["parameter"]
215239
field_type = self.fields.get(field_name, {}).get("type")
216-
require_type("sort", field_name, field_type, {"keyword", "long", "date"})
240+
require_type(
241+
"sort",
242+
field_name,
243+
field_type,
244+
{"keyword", "long", "date", "date_nanos"},
245+
)
217246
body["sort"].append({field_name: {"order": sort["direction"]}})
218247

219248
params = {}
@@ -226,17 +255,19 @@ async def search(
226255
)
227256
hits = [hit["_source"] for hit in response["hits"]["hits"]]
228257

258+
total_hits = response["hits"]["total"]["value"]
259+
229260
# Dates are returned as strings, convert them to Python datetimes
230261
for hit in hits:
231262
for field_name in hit:
232263
if field_name not in self.fields:
233264
continue
234-
if self.fields[field_name]["type"] == "date":
265+
if self.fields[field_name]["type"] in ["date", "date_nanos"]:
235266
hit[field_name] = datetime.strptime(
236267
hit[field_name], "%Y-%m-%dT%H:%M:%S.%f%z"
237268
)
238269

239-
return hits
270+
return total_hits, hits
240271

241272

242273
def require_type(operator, field_name, field_type, allowed_types):

diracx-db/tests/auth/test_authorization_flow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from sqlalchemy.exc import NoResultFound
55

66
from diracx.core.exceptions import AuthorizationError
7-
from diracx.db.sql import AuthDB
7+
from diracx.db.sql.auth.db import AuthDB
88

99
MAX_VALIDITY = 2
1010
EXPIRED = 0

diracx-db/tests/auth/test_device_flow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from sqlalchemy.exc import NoResultFound
88

99
from diracx.core.exceptions import AuthorizationError
10-
from diracx.db.sql import AuthDB
10+
from diracx.db.sql.auth.db import AuthDB
1111
from diracx.db.sql.auth.schema import USER_CODE_LENGTH
1212
from diracx.db.sql.utils.functions import substract_date
1313

diracx-db/tests/auth/test_refresh_token.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44
from uuid_utils import UUID, uuid7
55

6-
from diracx.db.sql import AuthDB
6+
from diracx.db.sql.auth.db import AuthDB
77
from diracx.db.sql.auth.schema import RefreshTokenStatus
88

99

0 commit comments

Comments
 (0)