deltafi 1.2.20__tar.gz → 2.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.

Potentially problematic release.


This version of deltafi might be problematic. Click here for more details.

Files changed (32) hide show
  1. {deltafi-1.2.20 → deltafi-2.0.0}/PKG-INFO +8 -6
  2. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/__init__.py +1 -1
  3. deltafi-2.0.0/deltafi/action.py +147 -0
  4. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/actioneventqueue.py +1 -1
  5. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/actiontype.py +3 -7
  6. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/domain.py +73 -63
  7. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/exception.py +1 -11
  8. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/genericmodel.py +4 -2
  9. deltafi-2.0.0/deltafi/input.py +52 -0
  10. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/logger.py +4 -4
  11. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/metric.py +2 -2
  12. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/plugin.py +112 -43
  13. deltafi-2.0.0/deltafi/result.py +287 -0
  14. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/storage.py +6 -1
  15. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/test_kit/__init__.py +1 -1
  16. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/test_kit/assertions.py +1 -1
  17. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/test_kit/compare_helpers.py +1 -1
  18. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/test_kit/constants.py +1 -1
  19. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/test_kit/egress.py +1 -1
  20. {deltafi-1.2.20 → deltafi-2.0.0}/deltafi/test_kit/framework.py +78 -69
  21. deltafi-2.0.0/deltafi/test_kit/transform.py +103 -0
  22. {deltafi-1.2.20 → deltafi-2.0.0}/pyproject.toml +9 -8
  23. deltafi-1.2.20/deltafi/action.py +0 -237
  24. deltafi-1.2.20/deltafi/input.py +0 -216
  25. deltafi-1.2.20/deltafi/result.py +0 -474
  26. deltafi-1.2.20/deltafi/test_kit/domain.py +0 -59
  27. deltafi-1.2.20/deltafi/test_kit/enrich.py +0 -70
  28. deltafi-1.2.20/deltafi/test_kit/format.py +0 -105
  29. deltafi-1.2.20/deltafi/test_kit/load.py +0 -128
  30. deltafi-1.2.20/deltafi/test_kit/transform.py +0 -75
  31. deltafi-1.2.20/deltafi/test_kit/validate.py +0 -54
  32. {deltafi-1.2.20 → deltafi-2.0.0}/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: deltafi
3
- Version: 1.2.20
3
+ Version: 2.0.0
4
4
  Summary: SDK for DeltaFi plugins and actions
5
5
  License: Apache License, Version 2.0
6
6
  Keywords: deltafi
@@ -17,14 +17,16 @@ Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Programming Language :: Python :: 3.10
18
18
  Classifier: Programming Language :: Python :: 3.11
19
19
  Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
20
21
  Classifier: Topic :: Software Development
22
+ Requires-Dist: PyYAML (==6.0.2)
21
23
  Requires-Dist: deepdiff (==6.7.1)
22
24
  Requires-Dist: json-logging (==1.3.0)
23
- Requires-Dist: minio (==7.2.5)
24
- Requires-Dist: pydantic (==2.7.1)
25
- Requires-Dist: redis (==5.0.4)
26
- Requires-Dist: requests (==2.31.0)
27
- Requires-Dist: urllib3 (==2.2.1)
25
+ Requires-Dist: minio (==7.2.10)
26
+ Requires-Dist: pydantic (==2.9.2)
27
+ Requires-Dist: redis (==5.2.0)
28
+ Requires-Dist: requests (==2.32.3)
29
+ Requires-Dist: urllib3 (==2.2.3)
28
30
  Project-URL: Bug Reports, https://chat.deltafi.org/deltafi/channels/bug-reports
29
31
  Project-URL: Documentation, https://docs.deltafi.org/#/
30
32
  Project-URL: Source Code, https://gitlab.com/deltafi/deltafi
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -0,0 +1,147 @@
1
+ #
2
+ # DeltaFi - Data transformation and enrichment platform
3
+ #
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ from abc import ABC, abstractmethod
20
+ from typing import Any, List
21
+
22
+ from deltafi.actiontype import ActionType
23
+ from deltafi.domain import Context, DeltaFileMessage
24
+ from deltafi.genericmodel import GenericModel
25
+ from deltafi.input import EgressInput, TransformInput
26
+ from deltafi.result import *
27
+ from pydantic import BaseModel
28
+
29
+
30
+ class Join(ABC):
31
+ def join(self, transform_inputs: List[TransformInput]):
32
+ all_content = []
33
+ all_metadata = {}
34
+ for transform_input in transform_inputs:
35
+ all_content += transform_input.content
36
+ all_metadata.update(transform_input.metadata)
37
+ return TransformInput(content=all_content, metadata=all_metadata)
38
+
39
+
40
+ class Action(ABC):
41
+ def __init__(self, action_type: ActionType, description: str, valid_result_types: tuple):
42
+ self.action_type = action_type
43
+ self.description = description
44
+ self.valid_result_types = valid_result_types
45
+ self.action_execution = None
46
+
47
+ @abstractmethod
48
+ def build_input(self, context: Context, delta_file_message: DeltaFileMessage):
49
+ pass
50
+
51
+ def execute_join_action(self, event):
52
+ raise RuntimeError(f"Join is not supported for {self.__class__.__name__}")
53
+
54
+ @abstractmethod
55
+ def execute(self, context: Context, action_input: Any, params: BaseModel):
56
+ pass
57
+
58
+ def execute_action(self, event):
59
+ if event.delta_file_messages is None or not len(event.delta_file_messages):
60
+ raise RuntimeError(f"Received event with no delta file messages for did {event.context.did}")
61
+ if event.context.join is not None:
62
+ result = self.execute_join_action(event)
63
+ else:
64
+ result = self.execute(
65
+ event.context,
66
+ self.build_input(event.context, event.delta_file_messages[0]),
67
+ self.param_class().model_validate(event.params))
68
+
69
+ self.validate_type(result)
70
+ return result
71
+
72
+ @staticmethod
73
+ def param_class():
74
+ """Factory method to create and return an empty GenericModel instance.
75
+
76
+ All action parameter classes must inherit pydantic.BaseModel.
77
+ Use of complex types in custom action parameter classes must specify
78
+ the internal types when defined. E.g., dict[str, str], or List[str]
79
+
80
+ Returns
81
+ -------
82
+ GenericModel
83
+ an empty GenericModel instance
84
+ """
85
+ return GenericModel
86
+
87
+ def validate_type(self, result):
88
+ if not isinstance(result, self.valid_result_types):
89
+ raise ValueError(f"{self.__class__.__name__} must return one of "
90
+ f"{[result_type.__name__ for result_type in self.valid_result_types]} "
91
+ f"but a {result.__class__.__name__} was returned")
92
+
93
+
94
+ class EgressAction(Action, ABC):
95
+ def __init__(self, description: str):
96
+ super().__init__(ActionType.EGRESS, description, (EgressResult, ErrorResult, FilterResult))
97
+
98
+ def build_input(self, context: Context, delta_file_message: DeltaFileMessage):
99
+ return EgressInput(content=delta_file_message.content_list[0], metadata=delta_file_message.metadata)
100
+
101
+ @abstractmethod
102
+ def egress(self, context: Context, params: BaseModel, egress_input: EgressInput):
103
+ pass
104
+
105
+ def execute(self, context: Context, egress_input: EgressInput, params: BaseModel):
106
+ return self.egress(context, params, egress_input)
107
+
108
+
109
+ class TimedIngressAction(Action, ABC):
110
+ def __init__(self, description: str):
111
+ super().__init__(ActionType.TIMED_INGRESS, description, (IngressResult, ErrorResult))
112
+
113
+ def build_input(self, context: Context, delta_file_message: DeltaFileMessage):
114
+ return None
115
+
116
+ @abstractmethod
117
+ def ingress(self, context: Context, params: BaseModel):
118
+ pass
119
+
120
+ def execute(self, context: Context, input_placeholder: Any, params: BaseModel):
121
+ return self.ingress(context, params)
122
+
123
+
124
+ class TransformAction(Action, ABC):
125
+ def __init__(self, description: str):
126
+ super().__init__(ActionType.TRANSFORM, description,
127
+ (TransformResult, TransformResults, ErrorResult, FilterResult))
128
+
129
+ def build_input(self, context: Context, delta_file_message: DeltaFileMessage):
130
+ return TransformInput(content=delta_file_message.content_list, metadata=delta_file_message.metadata)
131
+
132
+ def execute_join_action(self, event):
133
+ if isinstance(self, Join):
134
+ return self.execute(
135
+ event.context,
136
+ self.join([self.build_input(event.context, delta_file_message)
137
+ for delta_file_message in event.delta_file_messages]),
138
+ self.param_class().model_validate(event.params))
139
+ else:
140
+ super().execute_join_action(event)
141
+
142
+ @abstractmethod
143
+ def transform(self, context: Context, params: BaseModel, transform_input: TransformInput):
144
+ pass
145
+
146
+ def execute(self, context: Context, transform_input: TransformInput, params: BaseModel):
147
+ return self.transform(context, params, transform_input)
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -20,13 +20,9 @@ from enum import Enum
20
20
 
21
21
 
22
22
  class ActionType(Enum):
23
+ INGRESS = "INGRESS"
23
24
  TIMED_INGRESS = "TIMED_INGRESS"
24
25
  TRANSFORM = "TRANSFORM"
25
- LOAD = "LOAD"
26
- DOMAIN = "DOMAIN"
27
- ENRICH = "ENRICH"
28
- FORMAT = "FORMAT"
29
- VALIDATE = "VALIDATE"
30
26
  EGRESS = "EGRESS"
31
- DELETE = "DELETE"
27
+ PUBLISH = "PUBLISH"
32
28
  UNKNOWN = "UNKNOWN"
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import copy
20
20
  from datetime import datetime, timedelta, timezone
21
21
  from logging import Logger
22
22
  from typing import Dict, List, NamedTuple
23
+ from uuid import uuid4
23
24
 
24
25
  from deltafi.storage import ContentService, Segment
25
26
 
@@ -40,61 +41,88 @@ class ActionExecution(NamedTuple):
40
41
 
41
42
  class Context(NamedTuple):
42
43
  did: str
43
- action_flow: str
44
+ delta_file_name: str
45
+ data_source: str
46
+ flow_name: str
47
+ flow_id: str
44
48
  action_name: str
45
- source_filename: str
46
- ingress_flow: str
47
- egress_flow: str
48
- system: str
49
+ action_version: str
49
50
  hostname: str
51
+ system_name: str
50
52
  content_service: ContentService
51
- collect: dict = None
52
- collected_dids: List[str] = None
53
+ join: dict = None
54
+ joined_dids: List[str] = None
53
55
  memo: str = None
54
56
  logger: Logger = None
57
+ saved_content: List = []
55
58
 
56
59
  @classmethod
57
- def create(cls, context: dict, hostname: str, content_service: ContentService, logger: Logger):
60
+ def create(cls, context: dict, content_service: ContentService, logger: Logger):
58
61
  did = context['did']
59
- action_name_parts = context['name'].split(".")
60
- action_flow = action_name_parts[0]
61
- action_name = action_name_parts[1]
62
- if 'sourceFilename' in context:
63
- source_filename = context['sourceFilename']
62
+ if 'deltaFileName' in context:
63
+ delta_file_name = context['deltaFileName']
64
64
  else:
65
- source_filename = None
66
- ingress_flow = context['ingressFlow']
67
- if 'egressFlow' in context:
68
- egress_flow = context['egressFlow']
65
+ delta_file_name = None
66
+ if 'dataSource' in context:
67
+ data_source = context['dataSource']
69
68
  else:
70
- egress_flow = None
71
- system = context['systemName']
72
- if 'collect' in context:
73
- collect = context['collect']
69
+ data_source = None
70
+ if 'flowName' in context:
71
+ flow_name = context['flowName']
74
72
  else:
75
- collect = None
76
- if 'collectedDids' in context:
77
- collected_dids = context['collectedDids']
73
+ flow_name = None
74
+ if 'flowId' in context:
75
+ flow_id = context['flowId']
78
76
  else:
79
- collected_dids = None
77
+ flow_id = None
78
+ if 'actionName' in context:
79
+ action_name = context['actionName']
80
+ else:
81
+ action_name = None
82
+ if 'actionVersion' in context:
83
+ action_version = context['actionVersion']
84
+ else:
85
+ action_version = None
86
+ if 'hostname' in context:
87
+ hostname = context['hostname']
88
+ else:
89
+ hostname = None
90
+ if 'systemName' in context:
91
+ system_name = context['systemName']
92
+ else:
93
+ system_name = None
94
+ if 'join' in context:
95
+ join = context['join']
96
+ else:
97
+ join = None
98
+ if 'joinedDids' in context:
99
+ joined_dids = context['joinedDids']
100
+ else:
101
+ joined_dids = None
80
102
  if 'memo' in context:
81
103
  memo = context['memo']
82
104
  else:
83
105
  memo = None
106
+
84
107
  return Context(did=did,
85
- action_flow=action_flow,
108
+ delta_file_name=delta_file_name,
109
+ data_source=data_source,
110
+ flow_name=flow_name,
111
+ flow_id=flow_id,
86
112
  action_name=action_name,
87
- source_filename=source_filename,
88
- ingress_flow=ingress_flow,
89
- egress_flow=egress_flow,
90
- system=system,
113
+ action_version=action_version,
91
114
  hostname=hostname,
92
- content_service=content_service,
93
- collect=collect,
94
- collected_dids=collected_dids,
115
+ system_name=system_name,
116
+ join=join,
117
+ joined_dids=joined_dids,
95
118
  memo=memo,
119
+ content_service=content_service,
120
+ saved_content=[],
96
121
  logger=logger)
97
122
 
123
+ def child_context(self):
124
+ return self._replace(did=str(uuid4()))
125
+
98
126
 
99
127
  class Content:
100
128
  """
@@ -197,7 +225,6 @@ class Content:
197
225
 
198
226
  return new_segments
199
227
 
200
-
201
228
  def get_size(self):
202
229
  """
203
230
  Returns the size of the content in bytes.
@@ -264,6 +291,12 @@ class Content:
264
291
  """
265
292
  self.segments.extend(other_content.segments)
266
293
 
294
+ def get_segment_names(self):
295
+ segment_names = {}
296
+ for seg in self.segments:
297
+ segment_names[seg.id()] = seg
298
+ return segment_names
299
+
267
300
  def __eq__(self, other):
268
301
  if isinstance(other, Content):
269
302
  return (self.name == other.name and
@@ -296,41 +329,17 @@ class Content:
296
329
  content_service=content_service)
297
330
 
298
331
 
299
- class Domain(NamedTuple):
300
- name: str
301
- value: str
302
- media_type: str
303
-
304
- @classmethod
305
- def from_dict(cls, domain: dict):
306
- name = domain['name']
307
- if 'value' in domain:
308
- value = domain['value']
309
- else:
310
- value = None
311
- media_type = domain['mediaType']
312
- return Domain(name=name,
313
- value=value,
314
- media_type=media_type)
315
-
316
-
317
332
  class DeltaFileMessage(NamedTuple):
318
333
  metadata: Dict[str, str]
319
334
  content_list: List[Content]
320
- domains: List[Domain]
321
- enrichments: List[Domain]
322
335
 
323
336
  @classmethod
324
337
  def from_dict(cls, delta_file_message: dict, content_service: ContentService):
325
338
  metadata = delta_file_message['metadata']
326
339
  content_list = [Content.from_dict(content, content_service) for content in delta_file_message['contentList']]
327
- domains = [Domain.from_dict(domain) for domain in delta_file_message['domains']] if 'domains' in delta_file_message else []
328
- enrichments = [Domain.from_dict(domain) for domain in delta_file_message['enrichments']] if 'enrichments' in delta_file_message else []
329
340
 
330
341
  return DeltaFileMessage(metadata=metadata,
331
- content_list=content_list,
332
- domains=domains,
333
- enrichments=enrichments)
342
+ content_list=content_list)
334
343
 
335
344
 
336
345
  class Event(NamedTuple):
@@ -341,9 +350,10 @@ class Event(NamedTuple):
341
350
  return_address: str
342
351
 
343
352
  @classmethod
344
- def create(cls, event: dict, hostname: str, content_service: ContentService, logger: Logger):
345
- delta_file_messages = [DeltaFileMessage.from_dict(delta_file_message, content_service) for delta_file_message in event['deltaFileMessages']]
346
- context = Context.create(event['actionContext'], hostname, content_service, logger)
353
+ def create(cls, event: dict, content_service: ContentService, logger: Logger):
354
+ delta_file_messages = [DeltaFileMessage.from_dict(delta_file_message, content_service) for delta_file_message in
355
+ event['deltaFileMessages']]
356
+ context = Context.create(event['actionContext'], content_service, logger)
347
357
  params = event['actionParams']
348
358
  queue_name = None
349
359
  if 'queueName' in event:
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -23,16 +23,6 @@ class ExpectedContentException(RuntimeError):
23
23
  self.size = size
24
24
 
25
25
 
26
- class MissingDomainException(RuntimeError):
27
- def __init__(self, name):
28
- self.name = name
29
-
30
-
31
- class MissingEnrichmentException(RuntimeError):
32
- def __init__(self, name):
33
- self.name = name
34
-
35
-
36
26
  class MissingMetadataException(RuntimeError):
37
27
  def __init__(self, key):
38
28
  self.key = key
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -22,7 +22,9 @@
22
22
 
23
23
  Provides an empty subclass of pydantic.BaseModel.
24
24
 
25
- Starting Pydantic v2, the BaseModel cannot be directly instantiated. This class provides for instantiation of GenericModel objects that inherit from BaseModel.
25
+ All action parameter classes must inherit pydantic.BaseModel.
26
+
27
+ Starting Pydantic v2, the BaseModel cannot be directly instantiated. This class provides for instantiation of GenericModel objects that inherit from BaseModel.
26
28
 
27
29
  This class does not define fields for validation or any other purpose.
28
30
  """
@@ -0,0 +1,52 @@
1
+ #
2
+ # DeltaFi - Data transformation and enrichment platform
3
+ #
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ from deltafi.domain import *
20
+ from deltafi.exception import MissingMetadataException, ExpectedContentException
21
+
22
+ class EgressInput(NamedTuple):
23
+ content: Content
24
+ metadata: dict
25
+
26
+
27
+ class TransformInput(NamedTuple):
28
+ content: List[Content]
29
+ metadata: dict
30
+
31
+ def has_content(self) -> bool:
32
+ return len(self.content) > 0
33
+
34
+ def content_at(self, index: int) -> Content:
35
+ if len(self.content) < index + 1:
36
+ raise ExpectedContentException(index, len(self.content))
37
+ return self.content[index]
38
+
39
+ def first_content(self):
40
+ return self.content_at(0)
41
+
42
+ def get_metadata(self, key: str):
43
+ if key in self.metadata:
44
+ return self.metadata[key]
45
+ else:
46
+ raise MissingMetadataException(key)
47
+
48
+ def get_metadata_or_else(self, key: str, default: str) -> str:
49
+ if key in self.metadata:
50
+ return self.metadata[key]
51
+ else:
52
+ return default
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
18
18
 
19
19
  import logging
20
20
  import sys
21
- from datetime import datetime
21
+ from datetime import datetime, UTC
22
22
 
23
23
  import json_logging
24
24
 
25
25
 
26
26
  def get_logger(name: str = None) -> logging.Logger:
27
27
  logger = logging.getLogger(name)
28
- logger.setLevel(logging.DEBUG)
28
+ logger.setLevel(logging.INFO)
29
29
  logger.addHandler(logging.StreamHandler(sys.stdout))
30
30
  logger.propagate = False
31
31
 
@@ -42,7 +42,7 @@ def _sanitize_log_msg(record):
42
42
  class JSONLogFormatter(json_logging.JSONLogFormatter):
43
43
 
44
44
  def _format_log_object(self, record, request_util):
45
- utcnow = datetime.utcnow()
45
+ utcnow = datetime.now(UTC)
46
46
 
47
47
  json_log_object = {
48
48
  'timestamp': json_logging.util.iso_time_format(utcnow),
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # DeltaFi - Data transformation and enrichment platform
3
3
  #
4
- # Copyright 2021-2023 DeltaFi Contributors <deltafi@deltafi.org>
4
+ # Copyright 2021-2024 DeltaFi Contributors <deltafi@deltafi.org>
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ from typing import Dict, NamedTuple
22
22
  class Metric(NamedTuple):
23
23
  name: str
24
24
  value: int
25
- tags: Dict[str, str]
25
+ tags: Dict[str, str] = {}
26
26
 
27
27
  def json(self):
28
28
  return {