fluidattacks_core_logging 12.0.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.
- fluidattacks_core_logging-12.0.0/.envrc +1 -0
- fluidattacks_core_logging-12.0.0/.gitignore +5 -0
- fluidattacks_core_logging-12.0.0/PKG-INFO +15 -0
- fluidattacks_core_logging-12.0.0/build/default.nix +19 -0
- fluidattacks_core_logging-12.0.0/build/filter.nix +13 -0
- fluidattacks_core_logging-12.0.0/flake.lock +303 -0
- fluidattacks_core_logging-12.0.0/flake.nix +29 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/__init__.py +59 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/filters.py +23 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/formatters.py +173 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/handlers.py +186 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/presets.py +40 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/py.typed +0 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/sources/__init__.py +180 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/sources/types.py +13 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/sources/utils.py +37 -0
- fluidattacks_core_logging-12.0.0/fluidattacks_core/logging/utils.py +37 -0
- fluidattacks_core_logging-12.0.0/import-linter.cfg +26 -0
- fluidattacks_core_logging-12.0.0/mypy.ini +32 -0
- fluidattacks_core_logging-12.0.0/pyproject.toml +40 -0
- fluidattacks_core_logging-12.0.0/ruff.toml +45 -0
- fluidattacks_core_logging-12.0.0/tests/__init__.py +0 -0
- fluidattacks_core_logging-12.0.0/tests/test_logging.py +323 -0
- fluidattacks_core_logging-12.0.0/uv.lock +701 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
use_flake ".#python311.devShell"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fluidattacks_core_logging
|
|
3
|
+
Version: 12.0.0
|
|
4
|
+
Summary: Fluid Attacks Core Logging Library
|
|
5
|
+
Author-email: Development <development@fluidattacks.com>
|
|
6
|
+
License: MPL-2.0
|
|
7
|
+
Classifier: Development Status :: 1 - Planning
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Requires-Dist: python-json-logger>=3.3.0
|
|
15
|
+
Requires-Dist: simplejson>=3.20.1
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{ src, workspace_root }:
|
|
2
|
+
{
|
|
3
|
+
inherit src workspace_root;
|
|
4
|
+
root_path = "develops/fluidattacks-core/python/logging";
|
|
5
|
+
module_name = "fluidattacks_core";
|
|
6
|
+
pypi_token = {
|
|
7
|
+
method = "oidc";
|
|
8
|
+
};
|
|
9
|
+
override = {
|
|
10
|
+
checks = {
|
|
11
|
+
basedpyright = false;
|
|
12
|
+
};
|
|
13
|
+
configs = {
|
|
14
|
+
import_linter = ../import-linter.cfg;
|
|
15
|
+
mypy = ../mypy.ini;
|
|
16
|
+
ruff = ../ruff.toml;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nodes": {
|
|
3
|
+
"flake-parts": {
|
|
4
|
+
"inputs": {
|
|
5
|
+
"nixpkgs-lib": "nixpkgs-lib"
|
|
6
|
+
},
|
|
7
|
+
"locked": {
|
|
8
|
+
"lastModified": 1762810396,
|
|
9
|
+
"narHash": "sha256-dxFVgQPG+R72dkhXTtqUm7KpxElw3u6E+YlQ2WaDgt8=",
|
|
10
|
+
"owner": "hercules-ci",
|
|
11
|
+
"repo": "flake-parts",
|
|
12
|
+
"rev": "0bdadb1b265fb4143a75bd1ec7d8c915898a9923",
|
|
13
|
+
"type": "github"
|
|
14
|
+
},
|
|
15
|
+
"original": {
|
|
16
|
+
"owner": "hercules-ci",
|
|
17
|
+
"repo": "flake-parts",
|
|
18
|
+
"type": "github"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"nix_filter": {
|
|
22
|
+
"locked": {
|
|
23
|
+
"lastModified": 1757882181,
|
|
24
|
+
"narHash": "sha256-+cCxYIh2UNalTz364p+QYmWHs0P+6wDhiWR4jDIKQIU=",
|
|
25
|
+
"owner": "numtide",
|
|
26
|
+
"repo": "nix-filter",
|
|
27
|
+
"rev": "59c44d1909c72441144b93cf0f054be7fe764de5",
|
|
28
|
+
"type": "github"
|
|
29
|
+
},
|
|
30
|
+
"original": {
|
|
31
|
+
"owner": "numtide",
|
|
32
|
+
"repo": "nix-filter",
|
|
33
|
+
"type": "github"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"nixpkgs": {
|
|
37
|
+
"locked": {
|
|
38
|
+
"lastModified": 1758690382,
|
|
39
|
+
"narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=",
|
|
40
|
+
"owner": "nixos",
|
|
41
|
+
"repo": "nixpkgs",
|
|
42
|
+
"rev": "e643668fd71b949c53f8626614b21ff71a07379d",
|
|
43
|
+
"type": "github"
|
|
44
|
+
},
|
|
45
|
+
"original": {
|
|
46
|
+
"owner": "nixos",
|
|
47
|
+
"ref": "nixos-unstable",
|
|
48
|
+
"repo": "nixpkgs",
|
|
49
|
+
"type": "github"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"nixpkgs-lib": {
|
|
53
|
+
"locked": {
|
|
54
|
+
"lastModified": 1761765539,
|
|
55
|
+
"narHash": "sha256-b0yj6kfvO8ApcSE+QmA6mUfu8IYG6/uU28OFn4PaC8M=",
|
|
56
|
+
"owner": "nix-community",
|
|
57
|
+
"repo": "nixpkgs.lib",
|
|
58
|
+
"rev": "719359f4562934ae99f5443f20aa06c2ffff91fc",
|
|
59
|
+
"type": "github"
|
|
60
|
+
},
|
|
61
|
+
"original": {
|
|
62
|
+
"owner": "nix-community",
|
|
63
|
+
"repo": "nixpkgs.lib",
|
|
64
|
+
"type": "github"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"nixpkgs_2": {
|
|
68
|
+
"locked": {
|
|
69
|
+
"lastModified": 1758690382,
|
|
70
|
+
"narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=",
|
|
71
|
+
"owner": "nixos",
|
|
72
|
+
"repo": "nixpkgs",
|
|
73
|
+
"rev": "e643668fd71b949c53f8626614b21ff71a07379d",
|
|
74
|
+
"type": "github"
|
|
75
|
+
},
|
|
76
|
+
"original": {
|
|
77
|
+
"owner": "nixos",
|
|
78
|
+
"ref": "nixos-unstable",
|
|
79
|
+
"repo": "nixpkgs",
|
|
80
|
+
"type": "github"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"nixpkgs_3": {
|
|
84
|
+
"locked": {
|
|
85
|
+
"lastModified": 1761373498,
|
|
86
|
+
"narHash": "sha256-Q/uhWNvd7V7k1H1ZPMy/vkx3F8C13ZcdrKjO7Jv7v0c=",
|
|
87
|
+
"owner": "nixos",
|
|
88
|
+
"repo": "nixpkgs",
|
|
89
|
+
"rev": "6a08e6bb4e46ff7fcbb53d409b253f6bad8a28ce",
|
|
90
|
+
"type": "github"
|
|
91
|
+
},
|
|
92
|
+
"original": {
|
|
93
|
+
"owner": "nixos",
|
|
94
|
+
"ref": "nixos-unstable",
|
|
95
|
+
"repo": "nixpkgs",
|
|
96
|
+
"type": "github"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"nixpkgs_flake": {
|
|
100
|
+
"locked": {
|
|
101
|
+
"lastModified": 1778253243,
|
|
102
|
+
"narHash": "sha256-KkH2QvU6iRLDTGGEwH5jnMqHWj4zMTuHxi1S1zdr01w=",
|
|
103
|
+
"owner": "nixos",
|
|
104
|
+
"repo": "nixpkgs",
|
|
105
|
+
"rev": "4fcda7103530b23c5ca44286344912082aad4220",
|
|
106
|
+
"type": "github"
|
|
107
|
+
},
|
|
108
|
+
"original": {
|
|
109
|
+
"owner": "nixos",
|
|
110
|
+
"repo": "nixpkgs",
|
|
111
|
+
"type": "github"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"pyproject-build-systems": {
|
|
115
|
+
"inputs": {
|
|
116
|
+
"nixpkgs": "nixpkgs",
|
|
117
|
+
"pyproject-nix": "pyproject-nix",
|
|
118
|
+
"uv2nix": "uv2nix"
|
|
119
|
+
},
|
|
120
|
+
"locked": {
|
|
121
|
+
"lastModified": 1761781027,
|
|
122
|
+
"narHash": "sha256-YDvxPAm2WnxrznRqWwHLjryBGG5Ey1ATEJXrON+TWt8=",
|
|
123
|
+
"owner": "pyproject-nix",
|
|
124
|
+
"repo": "build-system-pkgs",
|
|
125
|
+
"rev": "795a980d25301e5133eca37adae37283ec3c8e66",
|
|
126
|
+
"type": "github"
|
|
127
|
+
},
|
|
128
|
+
"original": {
|
|
129
|
+
"owner": "pyproject-nix",
|
|
130
|
+
"repo": "build-system-pkgs",
|
|
131
|
+
"type": "github"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"pyproject-nix": {
|
|
135
|
+
"inputs": {
|
|
136
|
+
"nixpkgs": [
|
|
137
|
+
"python_builder",
|
|
138
|
+
"pyproject-build-systems",
|
|
139
|
+
"nixpkgs"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
"locked": {
|
|
143
|
+
"lastModified": 1758265079,
|
|
144
|
+
"narHash": "sha256-amLaLNwKSZPShQHzfgmc/9o76dU8xzN0743dWgvYlr8=",
|
|
145
|
+
"owner": "nix-community",
|
|
146
|
+
"repo": "pyproject.nix",
|
|
147
|
+
"rev": "02e9418fd4af638447dca4b17b1280da95527fc9",
|
|
148
|
+
"type": "github"
|
|
149
|
+
},
|
|
150
|
+
"original": {
|
|
151
|
+
"owner": "nix-community",
|
|
152
|
+
"repo": "pyproject.nix",
|
|
153
|
+
"type": "github"
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"pyproject-nix_2": {
|
|
157
|
+
"inputs": {
|
|
158
|
+
"nixpkgs": "nixpkgs_2"
|
|
159
|
+
},
|
|
160
|
+
"locked": {
|
|
161
|
+
"lastModified": 1762427963,
|
|
162
|
+
"narHash": "sha256-CkPlAbIQ87wmjy5qHibfzk4DmMGBNqFer+lLfXjpP5M=",
|
|
163
|
+
"owner": "pyproject-nix",
|
|
164
|
+
"repo": "pyproject.nix",
|
|
165
|
+
"rev": "4540ea004e04fcd12dd2738d51383d10f956f7b9",
|
|
166
|
+
"type": "github"
|
|
167
|
+
},
|
|
168
|
+
"original": {
|
|
169
|
+
"owner": "pyproject-nix",
|
|
170
|
+
"repo": "pyproject.nix",
|
|
171
|
+
"type": "github"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"pyproject-nix_3": {
|
|
175
|
+
"inputs": {
|
|
176
|
+
"nixpkgs": [
|
|
177
|
+
"python_builder",
|
|
178
|
+
"uv2nix",
|
|
179
|
+
"nixpkgs"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"locked": {
|
|
183
|
+
"lastModified": 1760402624,
|
|
184
|
+
"narHash": "sha256-jF6UKLs2uGc2rtved8Vrt58oTWjTQoAssuYs/0578Z4=",
|
|
185
|
+
"owner": "pyproject-nix",
|
|
186
|
+
"repo": "pyproject.nix",
|
|
187
|
+
"rev": "84c4ea102127c77058ea1ed7be7300261fafc7d2",
|
|
188
|
+
"type": "github"
|
|
189
|
+
},
|
|
190
|
+
"original": {
|
|
191
|
+
"owner": "pyproject-nix",
|
|
192
|
+
"repo": "pyproject.nix",
|
|
193
|
+
"type": "github"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"python_builder": {
|
|
197
|
+
"inputs": {
|
|
198
|
+
"nix_filter": "nix_filter",
|
|
199
|
+
"nixpkgs_flake": "nixpkgs_flake",
|
|
200
|
+
"pyproject-build-systems": "pyproject-build-systems",
|
|
201
|
+
"pyproject-nix": "pyproject-nix_2",
|
|
202
|
+
"shell-helpers": "shell-helpers",
|
|
203
|
+
"uv2nix": "uv2nix_2"
|
|
204
|
+
},
|
|
205
|
+
"locked": {
|
|
206
|
+
"dir": "common/utils/python-builder",
|
|
207
|
+
"lastModified": 1787078362,
|
|
208
|
+
"narHash": "sha256-HYL7Rn6SuNjYxkt/PwFLksZjsauCiY+ENbOWryLsIlw=",
|
|
209
|
+
"ref": "refs/heads/trunk",
|
|
210
|
+
"rev": "09fd25a13309eb5e3b5b2a061bb340df3ae5d281",
|
|
211
|
+
"shallow": true,
|
|
212
|
+
"type": "git",
|
|
213
|
+
"url": "ssh://git@gitlab.com/fluidattacks/universe"
|
|
214
|
+
},
|
|
215
|
+
"original": {
|
|
216
|
+
"dir": "common/utils/python-builder",
|
|
217
|
+
"rev": "09fd25a13309eb5e3b5b2a061bb340df3ae5d281",
|
|
218
|
+
"shallow": true,
|
|
219
|
+
"type": "git",
|
|
220
|
+
"url": "ssh://git@gitlab.com/fluidattacks/universe"
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
"root": {
|
|
224
|
+
"inputs": {
|
|
225
|
+
"python_builder": "python_builder"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"shell-helpers": {
|
|
229
|
+
"inputs": {
|
|
230
|
+
"flake-parts": "flake-parts",
|
|
231
|
+
"nixpkgs": [
|
|
232
|
+
"python_builder",
|
|
233
|
+
"nixpkgs_flake"
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
"locked": {
|
|
237
|
+
"dir": "common/utils/shell-helpers",
|
|
238
|
+
"lastModified": 1762806066,
|
|
239
|
+
"narHash": "sha256-Wz99Fl7SpPU1NkTHJ36XOo6DjOEAMXCw3ThRABOS2Hs=",
|
|
240
|
+
"ref": "refs/heads/trunk",
|
|
241
|
+
"rev": "d73cfdc7ae9e7f547e22a4481d4c2ccce38b26a8",
|
|
242
|
+
"shallow": true,
|
|
243
|
+
"type": "git",
|
|
244
|
+
"url": "ssh://git@gitlab.com/fluidattacks/universe"
|
|
245
|
+
},
|
|
246
|
+
"original": {
|
|
247
|
+
"dir": "common/utils/shell-helpers",
|
|
248
|
+
"rev": "d73cfdc7ae9e7f547e22a4481d4c2ccce38b26a8",
|
|
249
|
+
"shallow": true,
|
|
250
|
+
"type": "git",
|
|
251
|
+
"url": "ssh://git@gitlab.com/fluidattacks/universe"
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
"uv2nix": {
|
|
255
|
+
"inputs": {
|
|
256
|
+
"nixpkgs": [
|
|
257
|
+
"python_builder",
|
|
258
|
+
"pyproject-build-systems",
|
|
259
|
+
"nixpkgs"
|
|
260
|
+
],
|
|
261
|
+
"pyproject-nix": [
|
|
262
|
+
"python_builder",
|
|
263
|
+
"pyproject-build-systems",
|
|
264
|
+
"pyproject-nix"
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
"locked": {
|
|
268
|
+
"lastModified": 1758933732,
|
|
269
|
+
"narHash": "sha256-HAmm1GBS1myZCFuog0DC2ZLaynvZtiUI2Crmo+cdQI0=",
|
|
270
|
+
"owner": "pyproject-nix",
|
|
271
|
+
"repo": "uv2nix",
|
|
272
|
+
"rev": "273ce18f913d8559e0d04f820d724308966d7c4d",
|
|
273
|
+
"type": "github"
|
|
274
|
+
},
|
|
275
|
+
"original": {
|
|
276
|
+
"owner": "pyproject-nix",
|
|
277
|
+
"repo": "uv2nix",
|
|
278
|
+
"type": "github"
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
"uv2nix_2": {
|
|
282
|
+
"inputs": {
|
|
283
|
+
"nixpkgs": "nixpkgs_3",
|
|
284
|
+
"pyproject-nix": "pyproject-nix_3"
|
|
285
|
+
},
|
|
286
|
+
"locked": {
|
|
287
|
+
"lastModified": 1761872265,
|
|
288
|
+
"narHash": "sha256-i25GRgp2vUOebY70L3NTAgkd+Pr1hnn5xM3qHxH0ONU=",
|
|
289
|
+
"owner": "pyproject-nix",
|
|
290
|
+
"repo": "uv2nix",
|
|
291
|
+
"rev": "74dfb62871be152ad3673b143b0cc56105a4f3c5",
|
|
292
|
+
"type": "github"
|
|
293
|
+
},
|
|
294
|
+
"original": {
|
|
295
|
+
"owner": "pyproject-nix",
|
|
296
|
+
"repo": "uv2nix",
|
|
297
|
+
"type": "github"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
"root": "root",
|
|
302
|
+
"version": 7
|
|
303
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
description = "Fluid Attacks Core logging package.";
|
|
3
|
+
|
|
4
|
+
inputs = {
|
|
5
|
+
python_builder = {
|
|
6
|
+
url = "git+ssh://git@gitlab.com/fluidattacks/universe?shallow=1&rev=09fd25a13309eb5e3b5b2a061bb340df3ae5d281&dir=common/utils/python-builder";
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
outputs =
|
|
11
|
+
{ self, ... }@inputs:
|
|
12
|
+
let
|
|
13
|
+
build_args =
|
|
14
|
+
{
|
|
15
|
+
system,
|
|
16
|
+
python_version,
|
|
17
|
+
nixpkgs,
|
|
18
|
+
builders,
|
|
19
|
+
scripts,
|
|
20
|
+
}:
|
|
21
|
+
import ./build {
|
|
22
|
+
src = import ./build/filter.nix nixpkgs.nix-filter self;
|
|
23
|
+
workspace_root = ./.;
|
|
24
|
+
};
|
|
25
|
+
in
|
|
26
|
+
{
|
|
27
|
+
packages = inputs.python_builder.outputs.build build_args;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import logging.config
|
|
5
|
+
import sys
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from fluidattacks_core.logging.presets import DATE_FORMAT, PRODUCT_LOGGING
|
|
9
|
+
from fluidattacks_core.logging.sources.utils import (
|
|
10
|
+
set_commit_ref_name,
|
|
11
|
+
set_commit_sha,
|
|
12
|
+
set_product_environment,
|
|
13
|
+
set_product_id,
|
|
14
|
+
set_product_version,
|
|
15
|
+
)
|
|
16
|
+
from fluidattacks_core.logging.utils import set_telemetry_metadata
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from logging.config import _DictConfigArgs
|
|
20
|
+
from types import TracebackType
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def init_uncaught_exception_logging() -> None:
|
|
24
|
+
logger = logging.getLogger("unhandled")
|
|
25
|
+
|
|
26
|
+
def handle_uncaught_exception(
|
|
27
|
+
exception_type: type[BaseException],
|
|
28
|
+
msg: BaseException,
|
|
29
|
+
traceback: TracebackType | None,
|
|
30
|
+
) -> None:
|
|
31
|
+
if issubclass(exception_type, KeyboardInterrupt):
|
|
32
|
+
sys.__excepthook__(exception_type, msg, traceback)
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
logger.critical(
|
|
36
|
+
"Uncaught exception",
|
|
37
|
+
exc_info=(exception_type, msg, traceback),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
sys.excepthook = handle_uncaught_exception
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def init_logging(preset: _DictConfigArgs | None = None) -> None:
|
|
44
|
+
logging.config.dictConfig(preset or PRODUCT_LOGGING)
|
|
45
|
+
init_uncaught_exception_logging()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"DATE_FORMAT",
|
|
50
|
+
"PRODUCT_LOGGING",
|
|
51
|
+
"init_logging",
|
|
52
|
+
"init_uncaught_exception_logging",
|
|
53
|
+
"set_commit_ref_name",
|
|
54
|
+
"set_commit_sha",
|
|
55
|
+
"set_product_environment",
|
|
56
|
+
"set_product_id",
|
|
57
|
+
"set_product_version",
|
|
58
|
+
"set_telemetry_metadata",
|
|
59
|
+
]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from fluidattacks_core.logging.sources.utils import get_env_var, get_environment
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NoProductionFilter(logging.Filter):
|
|
7
|
+
def filter(self, _record: logging.LogRecord) -> bool:
|
|
8
|
+
return get_environment() != "production"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProductionOnlyFilter(logging.Filter):
|
|
12
|
+
def filter(self, _record: logging.LogRecord) -> bool:
|
|
13
|
+
return get_environment() == "production"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ErrorOnlyFilter(logging.Filter):
|
|
17
|
+
def filter(self, _record: logging.LogRecord) -> bool:
|
|
18
|
+
return _record.levelno >= logging.ERROR
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EnabledTelemetryFilter(logging.Filter):
|
|
22
|
+
def filter(self, _record: logging.LogRecord) -> bool:
|
|
23
|
+
return str(get_env_var("TELEMETRY_OPT_OUT")).lower() != "true"
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import traceback
|
|
3
|
+
from datetime import UTC, datetime
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
import simplejson as json
|
|
8
|
+
from pythonjsonlogger.json import JsonFormatter
|
|
9
|
+
|
|
10
|
+
from fluidattacks_core.logging.sources import (
|
|
11
|
+
BatchSource,
|
|
12
|
+
ContainerSource,
|
|
13
|
+
DefaultSource,
|
|
14
|
+
LambdaSource,
|
|
15
|
+
PipelineSource,
|
|
16
|
+
)
|
|
17
|
+
from fluidattacks_core.logging.utils import get_telemetry_metadata
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from fluidattacks_core.logging.sources.types import SourceStrategy
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ColorfulFormatter(logging.Formatter):
|
|
24
|
+
grey: str = "\x1b[38;1m"
|
|
25
|
+
yellow: str = "\x1b[33;1m"
|
|
26
|
+
red: str = "\x1b[31;1m"
|
|
27
|
+
reset: str = "\x1b[0m"
|
|
28
|
+
msg_format: str = "{asctime} [{levelname}] [{name}] {message}"
|
|
29
|
+
|
|
30
|
+
FORMATS = { # noqa: RUF012
|
|
31
|
+
logging.DEBUG: grey + msg_format + reset,
|
|
32
|
+
logging.INFO: msg_format,
|
|
33
|
+
logging.WARNING: yellow + msg_format + reset,
|
|
34
|
+
logging.ERROR: red + msg_format + reset,
|
|
35
|
+
logging.CRITICAL: red + msg_format + reset,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
39
|
+
log_fmt = self.FORMATS.get(record.levelno)
|
|
40
|
+
formatter = logging.Formatter(
|
|
41
|
+
log_fmt,
|
|
42
|
+
datefmt=self.datefmt,
|
|
43
|
+
style="{",
|
|
44
|
+
)
|
|
45
|
+
return formatter.format(record)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CustomJsonFormatter(JsonFormatter):
|
|
49
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
|
|
50
|
+
def json_default(object_: object) -> Any: # noqa: ANN401
|
|
51
|
+
if isinstance(object_, set):
|
|
52
|
+
return list(object_)
|
|
53
|
+
if isinstance(object_, datetime):
|
|
54
|
+
return object_.astimezone(tz=UTC).isoformat()
|
|
55
|
+
if isinstance(object_, float):
|
|
56
|
+
return Decimal(str(object_))
|
|
57
|
+
|
|
58
|
+
if hasattr(object_, "__dict__"):
|
|
59
|
+
try:
|
|
60
|
+
return {k: v for k, v in object_.__dict__.items() if not k.startswith("_")}
|
|
61
|
+
except (TypeError, ValueError, RecursionError):
|
|
62
|
+
return f"<{type(object_).__name__} object>"
|
|
63
|
+
|
|
64
|
+
return object_
|
|
65
|
+
|
|
66
|
+
super().__init__(*args, **kwargs, json_serializer=json.dumps, json_default=json_default)
|
|
67
|
+
|
|
68
|
+
def add_fields(
|
|
69
|
+
self,
|
|
70
|
+
log_record: dict[str, Any],
|
|
71
|
+
record: logging.LogRecord,
|
|
72
|
+
message_dict: dict[str, Any],
|
|
73
|
+
) -> None:
|
|
74
|
+
super().add_fields(log_record, record, message_dict)
|
|
75
|
+
|
|
76
|
+
log_record["timestamp"] = self._get_timestamp(log_record)
|
|
77
|
+
log_record["level"] = log_record.get("level") or record.levelname
|
|
78
|
+
log_record["name"] = record.name
|
|
79
|
+
log_record["file_location"] = f"{record.filename}:{record.lineno}"
|
|
80
|
+
log_record["lineno"] = record.lineno
|
|
81
|
+
|
|
82
|
+
self._add_source_fields(log_record)
|
|
83
|
+
|
|
84
|
+
self._add_default_telemetry_fields(log_record)
|
|
85
|
+
self._add_error_fields(log_record, record)
|
|
86
|
+
self._add_tracing_fields(log_record)
|
|
87
|
+
self._add_extra_fields(log_record)
|
|
88
|
+
|
|
89
|
+
def _get_timestamp(self, log_record: dict[str, Any]) -> int:
|
|
90
|
+
if timestamp := log_record.get("timestamp"):
|
|
91
|
+
if isinstance(timestamp, int):
|
|
92
|
+
return timestamp
|
|
93
|
+
if isinstance(timestamp, str) and timestamp.isdigit():
|
|
94
|
+
return int(timestamp)
|
|
95
|
+
return round(datetime.now(tz=UTC).timestamp() * 1000)
|
|
96
|
+
|
|
97
|
+
def _add_source_fields(self, log_record: dict[str, Any]) -> None:
|
|
98
|
+
"""Add source information to the log record.
|
|
99
|
+
|
|
100
|
+
It includes:
|
|
101
|
+
- Source
|
|
102
|
+
- Service
|
|
103
|
+
- Version
|
|
104
|
+
- Deployment environment
|
|
105
|
+
- Other metadata according to the source
|
|
106
|
+
"""
|
|
107
|
+
supported_sources: list[type[SourceStrategy]] = [
|
|
108
|
+
LambdaSource,
|
|
109
|
+
BatchSource,
|
|
110
|
+
PipelineSource,
|
|
111
|
+
ContainerSource,
|
|
112
|
+
DefaultSource,
|
|
113
|
+
]
|
|
114
|
+
for source in supported_sources:
|
|
115
|
+
if source.detect():
|
|
116
|
+
log_record.update(source.log_metadata())
|
|
117
|
+
break
|
|
118
|
+
|
|
119
|
+
def _add_default_telemetry_fields(self, log_record: dict[str, Any]) -> None:
|
|
120
|
+
"""Add default metadata fields to the log record.
|
|
121
|
+
|
|
122
|
+
Added fields via `set_telemetry_metadata` are included in this step.
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
for key, value in get_telemetry_metadata().items():
|
|
126
|
+
log_record[key] = value # noqa: PERF403
|
|
127
|
+
|
|
128
|
+
def _add_error_fields(self, log_record: dict[str, Any], record: logging.LogRecord) -> None:
|
|
129
|
+
"""Add error fields to the log record.
|
|
130
|
+
|
|
131
|
+
It includes:
|
|
132
|
+
- `error.kind`
|
|
133
|
+
- `error.message`
|
|
134
|
+
- `error.stack`
|
|
135
|
+
"""
|
|
136
|
+
if record.exc_info:
|
|
137
|
+
if exc_type := record.exc_info[0]:
|
|
138
|
+
log_record["error.kind"] = exc_type.__name__
|
|
139
|
+
if exc_value := record.exc_info[1]:
|
|
140
|
+
log_record["error.message"] = str(exc_value)
|
|
141
|
+
if exc_tb := record.exc_info[2]:
|
|
142
|
+
log_record["error.stack"] = "".join(traceback.format_tb(exc_tb))
|
|
143
|
+
|
|
144
|
+
# Remove duplicated info
|
|
145
|
+
log_record.pop("exc_info", None)
|
|
146
|
+
|
|
147
|
+
def _add_tracing_fields(self, log_record: dict[str, Any]) -> None:
|
|
148
|
+
"""Add tracing fields (by OpenTelemetry) to the log record.
|
|
149
|
+
|
|
150
|
+
It includes:
|
|
151
|
+
- `trace_id`
|
|
152
|
+
- `span_id`
|
|
153
|
+
- `trace_sampled`
|
|
154
|
+
"""
|
|
155
|
+
if log_record.get("otelTraceID") is not None:
|
|
156
|
+
log_record["trace_id"] = log_record.pop("otelTraceID")
|
|
157
|
+
|
|
158
|
+
if log_record.get("otelSpanID") is not None:
|
|
159
|
+
log_record["span_id"] = log_record.pop("otelSpanID")
|
|
160
|
+
|
|
161
|
+
if log_record.get("otelTraceSampled") is not None:
|
|
162
|
+
log_record["trace_sampled"] = log_record.pop("otelTraceSampled")
|
|
163
|
+
|
|
164
|
+
def _add_extra_fields(self, log_record: dict[str, Any]) -> None:
|
|
165
|
+
"""Add fields from `extra` to the log record.
|
|
166
|
+
|
|
167
|
+
It adds fields at the top level, allowing them to override existing fields.
|
|
168
|
+
"""
|
|
169
|
+
if log_record.get("extra") is None:
|
|
170
|
+
log_record.pop("extra", None)
|
|
171
|
+
elif isinstance(log_record.get("extra"), dict):
|
|
172
|
+
log_record.update(log_record["extra"])
|
|
173
|
+
log_record.pop("extra", None)
|