python-openobserve 0.5.1__tar.gz → 0.6.0__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.
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/PKG-INFO +22 -22
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/pyproject.toml +39 -39
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/python_openobserve/openobserve.py +111 -8
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/LICENSES/CC-BY-4.0.txt +0 -0
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/LICENSES/CC-BY-SA-4.0.txt +0 -0
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/LICENSES/GPL-3.0-or-later.txt +0 -0
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/README.md +0 -0
- {python_openobserve-0.5.1 → python_openobserve-0.6.0}/python_openobserve/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-openobserve
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: OpenObserve client for Python
|
|
5
5
|
License-File: LICENSES/CC-BY-4.0.txt
|
|
6
6
|
License-File: LICENSES/CC-BY-SA-4.0.txt
|
|
@@ -8,42 +8,42 @@ License-File: LICENSES/GPL-3.0-or-later.txt
|
|
|
8
8
|
Keywords: openobserve,elasticsearch,logging,unstructured data
|
|
9
9
|
Author: Justin Guese
|
|
10
10
|
Author-email: guese.justin@gmail.com
|
|
11
|
-
Requires-Python: >=3.
|
|
11
|
+
Requires-Python: >=3.11,<3.16
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
13
|
Provides-Extra: ci
|
|
14
14
|
Provides-Extra: docs
|
|
15
15
|
Provides-Extra: pandas
|
|
16
16
|
Provides-Extra: polars
|
|
17
17
|
Provides-Extra: tests
|
|
18
|
-
Requires-Dist: cryptography (>=
|
|
18
|
+
Requires-Dist: cryptography (>=50.0.0,<50.1.0)
|
|
19
19
|
Requires-Dist: h11 (>=0.16.0,<0.17.0)
|
|
20
20
|
Requires-Dist: httpcore (>=1.0.9,<1.1.0)
|
|
21
21
|
Requires-Dist: httpx (>=0.28,<1.0)
|
|
22
|
-
Requires-Dist: jmespath (==1.0
|
|
23
|
-
Requires-Dist: jmespath (==1.0
|
|
24
|
-
Requires-Dist: memray (==1.
|
|
22
|
+
Requires-Dist: jmespath (==1.1.0) ; extra == "ci"
|
|
23
|
+
Requires-Dist: jmespath (==1.1.0) ; extra == "tests"
|
|
24
|
+
Requires-Dist: memray (==1.20.0) ; extra == "ci"
|
|
25
25
|
Requires-Dist: mkdocs (==1.6.1) ; extra == "docs"
|
|
26
|
-
Requires-Dist: mkdocs-material (==9.
|
|
27
|
-
Requires-Dist: mkdocstrings (==0.
|
|
28
|
-
Requires-Dist: mypy (==
|
|
29
|
-
Requires-Dist: mypy-extensions (==1.
|
|
30
|
-
Requires-Dist: pandas (==
|
|
26
|
+
Requires-Dist: mkdocs-material (==9.8.0) ; extra == "docs"
|
|
27
|
+
Requires-Dist: mkdocstrings (==1.0.8) ; extra == "docs"
|
|
28
|
+
Requires-Dist: mypy (==2.4.1) ; extra == "ci"
|
|
29
|
+
Requires-Dist: mypy-extensions (==1.2.0) ; extra == "ci"
|
|
30
|
+
Requires-Dist: pandas (==3.1.1) ; extra == "ci"
|
|
31
31
|
Requires-Dist: pandas (>=2.2) ; extra == "pandas"
|
|
32
|
-
Requires-Dist: pandas-stubs (==
|
|
33
|
-
Requires-Dist: polars (==1.
|
|
34
|
-
Requires-Dist: protobuf (>=
|
|
32
|
+
Requires-Dist: pandas-stubs (==3.1.0.261029) ; extra == "ci"
|
|
33
|
+
Requires-Dist: polars (==2.1.0) ; extra == "polars"
|
|
34
|
+
Requires-Dist: protobuf (>=7.35.1)
|
|
35
35
|
Requires-Dist: pydantic (>=2.10,<3.0)
|
|
36
36
|
Requires-Dist: pyjwt (>=2.12.1,<3.0.0)
|
|
37
|
-
Requires-Dist: pytest (==9.0
|
|
38
|
-
Requires-Dist: pytest (==9.0
|
|
39
|
-
Requires-Dist: pytest-cov (==
|
|
40
|
-
Requires-Dist: pytest-memray (==1.
|
|
41
|
-
Requires-Dist: python-dotenv (==1.2.
|
|
42
|
-
Requires-Dist: python-dotenv (==1.2.
|
|
37
|
+
Requires-Dist: pytest (==9.2.0) ; extra == "ci"
|
|
38
|
+
Requires-Dist: pytest (==9.2.0) ; extra == "tests"
|
|
39
|
+
Requires-Dist: pytest-cov (==7.1.0) ; extra == "ci"
|
|
40
|
+
Requires-Dist: pytest-memray (==1.11.0) ; extra == "ci"
|
|
41
|
+
Requires-Dist: python-dotenv (==1.2.4) ; extra == "ci"
|
|
42
|
+
Requires-Dist: python-dotenv (==1.2.4) ; extra == "tests"
|
|
43
43
|
Requires-Dist: python-multipart (>=0.0.22)
|
|
44
44
|
Requires-Dist: requests (>=2.33.0,<3.0.0)
|
|
45
|
-
Requires-Dist: sqlglot (>=
|
|
46
|
-
Requires-Dist: types-jmespath (==1.0.
|
|
45
|
+
Requires-Dist: sqlglot (>=30.29.0,<30.30.0)
|
|
46
|
+
Requires-Dist: types-jmespath (==1.1.0.20260724) ; extra == "ci"
|
|
47
47
|
Project-URL: Homepage, https://github.com/JustinGuese/python-openobserve
|
|
48
48
|
Project-URL: Repository, https://github.com/JustinGuese/python-openobserve
|
|
49
49
|
Description-Content-Type: text/markdown
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "python-openobserve"
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.6.0"
|
|
7
7
|
description = "OpenObserve client for Python"
|
|
8
8
|
readme = "README.md"
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.11,<3.16"
|
|
10
10
|
license-files = [
|
|
11
11
|
"LICENSES/CC-BY-4.0.txt",
|
|
12
12
|
"LICENSES/CC-BY-SA-4.0.txt",
|
|
@@ -19,14 +19,14 @@ classifiers = [
|
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
dependencies = [
|
|
22
|
-
"cryptography (>=
|
|
22
|
+
"cryptography (>=50.0.0,<50.1.0)",
|
|
23
23
|
"h11~=0.16.0",
|
|
24
24
|
"httpcore~=1.0.9",
|
|
25
25
|
"httpx~=0.28",
|
|
26
|
-
"protobuf>=
|
|
26
|
+
"protobuf>=7.35.1",
|
|
27
27
|
"pydantic~=2.10",
|
|
28
28
|
"python-multipart>=0.0.22",
|
|
29
|
-
"sqlglot~=
|
|
29
|
+
"sqlglot~=30.29.0",
|
|
30
30
|
"pyjwt (>=2.12.1,<3.0.0)",
|
|
31
31
|
"requests (>=2.33.0,<3.0.0)",
|
|
32
32
|
]
|
|
@@ -40,56 +40,56 @@ python_openobserve = "python_openobserve:openobserve"
|
|
|
40
40
|
|
|
41
41
|
[project.optional-dependencies]
|
|
42
42
|
ci = [
|
|
43
|
-
"jmespath==1.0
|
|
44
|
-
"memray==1.
|
|
45
|
-
"pytest-memray==1.
|
|
46
|
-
"mypy==
|
|
47
|
-
"mypy-extensions==1.
|
|
48
|
-
"pandas==
|
|
49
|
-
"pandas-stubs==
|
|
50
|
-
"pytest==9.0
|
|
51
|
-
"pytest-cov==
|
|
52
|
-
"python-dotenv==1.2.
|
|
53
|
-
"types-jmespath==1.0.
|
|
43
|
+
"jmespath==1.1.0",
|
|
44
|
+
"memray==1.20.0",
|
|
45
|
+
"pytest-memray==1.11.0",
|
|
46
|
+
"mypy==2.4.1",
|
|
47
|
+
"mypy-extensions==1.2.0",
|
|
48
|
+
"pandas==3.1.1",
|
|
49
|
+
"pandas-stubs==3.1.0.261029",
|
|
50
|
+
"pytest==9.2.0",
|
|
51
|
+
"pytest-cov==7.1.0",
|
|
52
|
+
"python-dotenv==1.2.4",
|
|
53
|
+
"types-jmespath==1.1.0.20260724",
|
|
54
54
|
]
|
|
55
55
|
docs = [
|
|
56
56
|
"mkdocs==1.6.1",
|
|
57
|
-
"mkdocs-material==9.
|
|
58
|
-
"mkdocstrings==0.
|
|
57
|
+
"mkdocs-material==9.8.0",
|
|
58
|
+
"mkdocstrings==1.0.8",
|
|
59
59
|
]
|
|
60
|
-
tests = ["pytest==9.0
|
|
60
|
+
tests = ["pytest==9.2.0", "jmespath==1.1.0", "python-dotenv==1.2.4"]
|
|
61
61
|
pandas = ["pandas>=2.2"]
|
|
62
|
-
polars = ["polars==1.
|
|
62
|
+
polars = ["polars==2.1.0"]
|
|
63
63
|
|
|
64
64
|
[tool.poetry.group.test.dependencies]
|
|
65
|
-
pytest = "
|
|
66
|
-
jmespath = "
|
|
67
|
-
python-dotenv = "
|
|
65
|
+
pytest = "*"
|
|
66
|
+
jmespath = "*"
|
|
67
|
+
python-dotenv = "*"
|
|
68
68
|
|
|
69
69
|
[tool.poetry.group.docs.dependencies]
|
|
70
|
-
mkdocs = "
|
|
71
|
-
mkdocs-material = "
|
|
72
|
-
mkdocstrings = "
|
|
70
|
+
mkdocs = "*"
|
|
71
|
+
mkdocs-material = "*"
|
|
72
|
+
mkdocstrings = "*"
|
|
73
73
|
|
|
74
74
|
[tool.poetry.group.ci.dependencies]
|
|
75
|
-
jmespath = "
|
|
76
|
-
memray = "
|
|
77
|
-
pytest-memray = "
|
|
78
|
-
mypy = "
|
|
79
|
-
mypy-extensions = "
|
|
80
|
-
pandas = "
|
|
81
|
-
openpyxl = "
|
|
82
|
-
pandas-stubs = "
|
|
83
|
-
pytest = "
|
|
84
|
-
pytest-cov = "
|
|
85
|
-
python-dotenv = "
|
|
86
|
-
types-jmespath = "
|
|
75
|
+
jmespath = "*"
|
|
76
|
+
memray = "*"
|
|
77
|
+
pytest-memray = "*"
|
|
78
|
+
mypy = "*"
|
|
79
|
+
mypy-extensions = "*"
|
|
80
|
+
pandas = "*"
|
|
81
|
+
openpyxl = "*"
|
|
82
|
+
pandas-stubs = "*"
|
|
83
|
+
pytest = "*"
|
|
84
|
+
pytest-cov = "*"
|
|
85
|
+
python-dotenv = "*"
|
|
86
|
+
types-jmespath = "*"
|
|
87
87
|
|
|
88
88
|
[tool.poetry.group.pandas.dependencies]
|
|
89
89
|
pandas = ">2.2"
|
|
90
90
|
|
|
91
91
|
[tool.poetry.group.polars.dependencies]
|
|
92
|
-
polars = "
|
|
92
|
+
polars = "*"
|
|
93
93
|
|
|
94
94
|
[build-system]
|
|
95
95
|
requires = ["poetry-core"]
|
|
@@ -15,11 +15,11 @@ import json
|
|
|
15
15
|
import os
|
|
16
16
|
import sys
|
|
17
17
|
import re
|
|
18
|
-
from datetime import datetime
|
|
18
|
+
from datetime import datetime, timedelta
|
|
19
19
|
from typing import List, Dict, Union, Optional, Any, cast
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
|
|
22
|
-
import httpx
|
|
22
|
+
import httpx # type: ignore
|
|
23
23
|
import sqlglot # type: ignore
|
|
24
24
|
|
|
25
25
|
try:
|
|
@@ -33,7 +33,7 @@ except ImportError:
|
|
|
33
33
|
HAVE_MODULE_PANDAS = False
|
|
34
34
|
|
|
35
35
|
try:
|
|
36
|
-
import polars
|
|
36
|
+
import polars # type: ignore
|
|
37
37
|
|
|
38
38
|
HAVE_MODULE_POLARS = True
|
|
39
39
|
except ImportError:
|
|
@@ -437,7 +437,7 @@ class OpenObserve:
|
|
|
437
437
|
try:
|
|
438
438
|
# ensure timestamp format
|
|
439
439
|
if col in ["_timestamp"] + timestamp_columns:
|
|
440
|
-
df_res
|
|
440
|
+
df_res = df_res.with_columns(polars.col(col).str.to_datetime())
|
|
441
441
|
except Exception as err:
|
|
442
442
|
raise Exception(
|
|
443
443
|
err,
|
|
@@ -446,6 +446,112 @@ class OpenObserve:
|
|
|
446
446
|
) from err
|
|
447
447
|
return df_res
|
|
448
448
|
|
|
449
|
+
# pylint: disable=R0914
|
|
450
|
+
def search2export(
|
|
451
|
+
self,
|
|
452
|
+
sql: str,
|
|
453
|
+
file_prefix: str,
|
|
454
|
+
*,
|
|
455
|
+
start_time: datetime = datetime.now(),
|
|
456
|
+
end_time: datetime = datetime.now(),
|
|
457
|
+
export_format: str = "json",
|
|
458
|
+
split_period: str = "D",
|
|
459
|
+
verbosity: int = 0,
|
|
460
|
+
timeout: int = 300,
|
|
461
|
+
timestamp_conversion_auto: bool = False,
|
|
462
|
+
) -> bool:
|
|
463
|
+
"""
|
|
464
|
+
OpenObserve search export function
|
|
465
|
+
Split options to manage large volume
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
sql: input sql query
|
|
469
|
+
start_time: start of search interval, either datetime, either int/epoch
|
|
470
|
+
end_time: end of search interval, either datetime, either int/epoch
|
|
471
|
+
export_format: raw json from OpenObserve (json) or csv
|
|
472
|
+
split_period: interval per file, H, D, W or M
|
|
473
|
+
file_prefix: file prefix for export
|
|
474
|
+
verbosity: how verbose to run from 0/less to 5/more
|
|
475
|
+
timeout: http timeout
|
|
476
|
+
timestamp_conversion_auto: try to convert automatically column containing time as name
|
|
477
|
+
timestamp_columns: convert given columns to timestamp
|
|
478
|
+
"""
|
|
479
|
+
if not file_prefix:
|
|
480
|
+
print(f"FATAL! no file_prefix input: {file_prefix}")
|
|
481
|
+
return False
|
|
482
|
+
period_start = start_time
|
|
483
|
+
interval = timedelta(days=1)
|
|
484
|
+
time_fmt = "%Y-%m-%dT%H:%M"
|
|
485
|
+
if split_period == "H":
|
|
486
|
+
interval = timedelta(hours=1)
|
|
487
|
+
if split_period == "W":
|
|
488
|
+
interval = timedelta(weeks=1)
|
|
489
|
+
time_fmt = "%Y-%m-%d"
|
|
490
|
+
# FIXME! timedelta does not support months input
|
|
491
|
+
# alternative: relativedelta but extra dependency
|
|
492
|
+
# if split_period == "M":
|
|
493
|
+
# interval = timedelta(months=1)
|
|
494
|
+
# time_fmt = "%Y-%m-%d"
|
|
495
|
+
if split_period not in ("H", "D", "W"):
|
|
496
|
+
print(f"FATAL! invalid split period input: {split_period}")
|
|
497
|
+
return False
|
|
498
|
+
period_end = start_time + interval
|
|
499
|
+
|
|
500
|
+
if export_format == "json":
|
|
501
|
+
while period_end < end_time:
|
|
502
|
+
file_name = (
|
|
503
|
+
f"{file_prefix}--"
|
|
504
|
+
f"{period_start.strftime(time_fmt)}--{period_end.strftime(time_fmt)}"
|
|
505
|
+
"--export.json"
|
|
506
|
+
)
|
|
507
|
+
res_json = self.search(
|
|
508
|
+
sql,
|
|
509
|
+
start_time=period_start,
|
|
510
|
+
end_time=period_end,
|
|
511
|
+
query_size=1000000000000,
|
|
512
|
+
verbosity=verbosity,
|
|
513
|
+
timeout=timeout,
|
|
514
|
+
timestamp_conversion_auto=timestamp_conversion_auto,
|
|
515
|
+
# leaving conversion to pandas
|
|
516
|
+
# timestamp_columns=timestamp_columns,
|
|
517
|
+
)
|
|
518
|
+
with open(
|
|
519
|
+
file_name,
|
|
520
|
+
"w",
|
|
521
|
+
encoding="utf-8",
|
|
522
|
+
) as f:
|
|
523
|
+
json.dump(res_json, f)
|
|
524
|
+
# loop
|
|
525
|
+
period_start = period_end
|
|
526
|
+
period_end = period_start + interval
|
|
527
|
+
if export_format == "csv":
|
|
528
|
+
while period_end < end_time:
|
|
529
|
+
file_name = (
|
|
530
|
+
f"{file_prefix}--"
|
|
531
|
+
f"{period_start.strftime(time_fmt)}--{period_end.strftime(time_fmt)}"
|
|
532
|
+
"--export.csv"
|
|
533
|
+
)
|
|
534
|
+
df_res = self.search2df(
|
|
535
|
+
sql,
|
|
536
|
+
start_time=period_start,
|
|
537
|
+
end_time=period_end,
|
|
538
|
+
query_size=1000000000000,
|
|
539
|
+
verbosity=verbosity,
|
|
540
|
+
timeout=timeout,
|
|
541
|
+
timestamp_conversion_auto=timestamp_conversion_auto,
|
|
542
|
+
# leaving conversion to pandas
|
|
543
|
+
# timestamp_columns=timestamp_columns,
|
|
544
|
+
)
|
|
545
|
+
df_res.to_csv(
|
|
546
|
+
file_name,
|
|
547
|
+
index=False,
|
|
548
|
+
)
|
|
549
|
+
# loop
|
|
550
|
+
period_start = period_end
|
|
551
|
+
period_end = period_start + interval
|
|
552
|
+
|
|
553
|
+
return True
|
|
554
|
+
|
|
449
555
|
# pylint: disable=too-many-branches,too-many-locals
|
|
450
556
|
def export_objects_split(
|
|
451
557
|
self,
|
|
@@ -603,7 +709,6 @@ class OpenObserve:
|
|
|
603
709
|
for name, df in data.items():
|
|
604
710
|
df.to_excel(f"{file_path}{name}.xlsx")
|
|
605
711
|
else: # default json
|
|
606
|
-
|
|
607
712
|
if split is True and flat is False:
|
|
608
713
|
# split json
|
|
609
714
|
data = {
|
|
@@ -627,9 +732,7 @@ class OpenObserve:
|
|
|
627
732
|
sys.exit(1)
|
|
628
733
|
else:
|
|
629
734
|
data = {
|
|
630
|
-
name: self.list_objects(
|
|
631
|
-
api_path, verbosity=verbosity
|
|
632
|
-
) # type: ignore[misc]
|
|
735
|
+
name: self.list_objects(api_path, verbosity=verbosity) # type: ignore[misc]
|
|
633
736
|
for name, api_path in object_types.items()
|
|
634
737
|
}
|
|
635
738
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|