ddeutil-workflow 0.0.33__py3-none-any.whl → 0.0.35__py3-none-any.whl
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.
- ddeutil/workflow/__about__.py +1 -1
- ddeutil/workflow/__init__.py +19 -10
- ddeutil/workflow/api/api.py +13 -8
- ddeutil/workflow/api/routes/__init__.py +8 -0
- ddeutil/workflow/api/routes/logs.py +36 -0
- ddeutil/workflow/api/{route.py → routes/schedules.py} +2 -131
- ddeutil/workflow/api/routes/workflows.py +137 -0
- ddeutil/workflow/audit.py +28 -37
- ddeutil/workflow/{hook.py → caller.py} +27 -27
- ddeutil/workflow/conf.py +47 -12
- ddeutil/workflow/job.py +149 -138
- ddeutil/workflow/logs.py +214 -0
- ddeutil/workflow/params.py +40 -12
- ddeutil/workflow/result.py +40 -61
- ddeutil/workflow/scheduler.py +185 -163
- ddeutil/workflow/{stage.py → stages.py} +105 -42
- ddeutil/workflow/utils.py +20 -2
- ddeutil/workflow/workflow.py +142 -117
- {ddeutil_workflow-0.0.33.dist-info → ddeutil_workflow-0.0.35.dist-info}/METADATA +36 -32
- ddeutil_workflow-0.0.35.dist-info/RECORD +30 -0
- {ddeutil_workflow-0.0.33.dist-info → ddeutil_workflow-0.0.35.dist-info}/WHEEL +1 -1
- ddeutil_workflow-0.0.33.dist-info/RECORD +0 -26
- {ddeutil_workflow-0.0.33.dist-info → ddeutil_workflow-0.0.35.dist-info}/LICENSE +0 -0
- {ddeutil_workflow-0.0.33.dist-info → ddeutil_workflow-0.0.35.dist-info}/top_level.txt +0 -0
ddeutil/workflow/__about__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__: str = "0.0.
|
1
|
+
__version__: str = "0.0.35"
|
ddeutil/workflow/__init__.py
CHANGED
@@ -9,6 +9,13 @@ from .audit import (
|
|
9
9
|
Audit,
|
10
10
|
get_audit,
|
11
11
|
)
|
12
|
+
from .caller import (
|
13
|
+
ReturnTagFunc,
|
14
|
+
TagFunc,
|
15
|
+
extract_call,
|
16
|
+
make_registry,
|
17
|
+
tag,
|
18
|
+
)
|
12
19
|
from .conf import (
|
13
20
|
Config,
|
14
21
|
Loader,
|
@@ -28,17 +35,15 @@ from .exceptions import (
|
|
28
35
|
UtilException,
|
29
36
|
WorkflowException,
|
30
37
|
)
|
31
|
-
from .hook import (
|
32
|
-
ReturnTagFunc,
|
33
|
-
TagFunc,
|
34
|
-
extract_hook,
|
35
|
-
make_registry,
|
36
|
-
tag,
|
37
|
-
)
|
38
38
|
from .job import (
|
39
39
|
Job,
|
40
40
|
Strategy,
|
41
41
|
)
|
42
|
+
from .logs import (
|
43
|
+
TraceLog,
|
44
|
+
get_dt_tznow,
|
45
|
+
get_trace,
|
46
|
+
)
|
42
47
|
from .params import (
|
43
48
|
ChoiceParam,
|
44
49
|
DatetimeParam,
|
@@ -46,7 +51,11 @@ from .params import (
|
|
46
51
|
Param,
|
47
52
|
StrParam,
|
48
53
|
)
|
49
|
-
from .result import
|
54
|
+
from .result import (
|
55
|
+
Result,
|
56
|
+
Status,
|
57
|
+
default_gen_id,
|
58
|
+
)
|
50
59
|
from .scheduler import (
|
51
60
|
Schedule,
|
52
61
|
ScheduleWorkflow,
|
@@ -54,10 +63,10 @@ from .scheduler import (
|
|
54
63
|
schedule_runner,
|
55
64
|
schedule_task,
|
56
65
|
)
|
57
|
-
from .
|
66
|
+
from .stages import (
|
58
67
|
BashStage,
|
68
|
+
CallStage,
|
59
69
|
EmptyStage,
|
60
|
-
HookStage,
|
61
70
|
PyStage,
|
62
71
|
Stage,
|
63
72
|
TriggerStage,
|
ddeutil/workflow/api/api.py
CHANGED
@@ -20,6 +20,7 @@ from ..conf import config, get_logger
|
|
20
20
|
from ..scheduler import ReleaseThread, ReleaseThreads
|
21
21
|
from ..workflow import ReleaseQueue, WorkflowTask
|
22
22
|
from .repeat import repeat_at
|
23
|
+
from .routes import log
|
23
24
|
|
24
25
|
load_dotenv()
|
25
26
|
logger = get_logger("ddeutil.workflow")
|
@@ -77,22 +78,26 @@ async def health():
|
|
77
78
|
return {"message": "Workflow API already start up"}
|
78
79
|
|
79
80
|
|
80
|
-
# NOTE
|
81
|
+
# NOTE Add the logs route by default.
|
82
|
+
app.include_router(log, prefix=config.prefix_path)
|
83
|
+
|
84
|
+
|
85
|
+
# NOTE: Enable the workflows route.
|
81
86
|
if config.enable_route_workflow:
|
82
|
-
from .
|
87
|
+
from .routes import workflow
|
83
88
|
|
84
|
-
app.include_router(
|
89
|
+
app.include_router(workflow, prefix=config.prefix_path)
|
85
90
|
|
86
91
|
|
87
|
-
# NOTE: Enable the
|
92
|
+
# NOTE: Enable the schedules route.
|
88
93
|
if config.enable_route_schedule:
|
89
94
|
from ..audit import get_audit
|
90
95
|
from ..scheduler import schedule_task
|
91
|
-
from .
|
96
|
+
from .routes import schedule
|
92
97
|
|
93
|
-
app.include_router(
|
98
|
+
app.include_router(schedule, prefix=config.prefix_path)
|
94
99
|
|
95
|
-
@
|
100
|
+
@schedule.on_event("startup")
|
96
101
|
@repeat_at(cron="* * * * *", delay=2)
|
97
102
|
def scheduler_listener():
|
98
103
|
"""Schedule broker every minute at 02 second."""
|
@@ -109,7 +114,7 @@ if config.enable_route_schedule:
|
|
109
114
|
log=get_audit(),
|
110
115
|
)
|
111
116
|
|
112
|
-
@
|
117
|
+
@schedule.on_event("startup")
|
113
118
|
@repeat_at(cron="*/5 * * * *", delay=10)
|
114
119
|
def monitoring():
|
115
120
|
logger.debug("[MONITOR]: Start monitoring threading.")
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# ------------------------------------------------------------------------------
|
2
|
+
# Copyright (c) 2022 Korawich Anuttra. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See LICENSE in the project root for
|
4
|
+
# license information.
|
5
|
+
# ------------------------------------------------------------------------------
|
6
|
+
from .logs import log_route as log
|
7
|
+
from .schedules import schedule_route as schedule
|
8
|
+
from .workflows import workflow_route as workflow
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# ------------------------------------------------------------------------------
|
2
|
+
# Copyright (c) 2022 Korawich Anuttra. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See LICENSE in the project root for
|
4
|
+
# license information.
|
5
|
+
# ------------------------------------------------------------------------------
|
6
|
+
from __future__ import annotations
|
7
|
+
|
8
|
+
from fastapi import APIRouter
|
9
|
+
from fastapi.responses import UJSONResponse
|
10
|
+
|
11
|
+
from ...conf import get_logger
|
12
|
+
from ...logs import get_trace_obj
|
13
|
+
|
14
|
+
logger = get_logger("ddeutil.workflow")
|
15
|
+
|
16
|
+
|
17
|
+
# NOTE: Start create the schedule routes.
|
18
|
+
#
|
19
|
+
log_route = APIRouter(
|
20
|
+
prefix="/logs",
|
21
|
+
tags=["logs"],
|
22
|
+
default_response_class=UJSONResponse,
|
23
|
+
)
|
24
|
+
|
25
|
+
|
26
|
+
@log_route.get(path="/")
|
27
|
+
async def get_logs():
|
28
|
+
return {
|
29
|
+
"message": "Getting logs",
|
30
|
+
"audits": list(get_trace_obj().find_logs()),
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
@log_route.get(path="/{run_id}")
|
35
|
+
async def get_log_with_run_id(run_id: str):
|
36
|
+
return get_trace_obj().find_log_with_id(run_id)
|
@@ -6,30 +6,17 @@
|
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
8
|
import copy
|
9
|
-
from dataclasses import asdict
|
10
9
|
from datetime import datetime, timedelta
|
11
|
-
from typing import Any
|
12
10
|
|
13
11
|
from fastapi import APIRouter, HTTPException, Request
|
14
12
|
from fastapi import status as st
|
15
13
|
from fastapi.responses import UJSONResponse
|
16
|
-
from pydantic import BaseModel
|
17
14
|
|
18
|
-
from
|
19
|
-
from
|
20
|
-
from ..conf import Loader, config, get_logger
|
21
|
-
from ..result import Result
|
22
|
-
from ..scheduler import Schedule
|
23
|
-
from ..workflow import Workflow
|
15
|
+
from ...conf import config, get_logger
|
16
|
+
from ...scheduler import Schedule
|
24
17
|
|
25
18
|
logger = get_logger("ddeutil.workflow")
|
26
19
|
|
27
|
-
workflow_route = APIRouter(
|
28
|
-
prefix="/workflows",
|
29
|
-
tags=["workflows"],
|
30
|
-
default_response_class=UJSONResponse,
|
31
|
-
)
|
32
|
-
|
33
20
|
schedule_route = APIRouter(
|
34
21
|
prefix="/schedules",
|
35
22
|
tags=["schedules"],
|
@@ -37,122 +24,6 @@ schedule_route = APIRouter(
|
|
37
24
|
)
|
38
25
|
|
39
26
|
|
40
|
-
@workflow_route.get(path="/")
|
41
|
-
async def get_workflows() -> DictData:
|
42
|
-
"""Return all workflow workflows that exists in config path."""
|
43
|
-
workflows: DictData = dict(Loader.finds(Workflow))
|
44
|
-
return {
|
45
|
-
"message": f"Getting all workflows: {len(workflows)}",
|
46
|
-
"count": len(workflows),
|
47
|
-
"workflows": workflows,
|
48
|
-
}
|
49
|
-
|
50
|
-
|
51
|
-
@workflow_route.get(path="/{name}")
|
52
|
-
async def get_workflow_by_name(name: str) -> DictData:
|
53
|
-
"""Return model of workflow that passing an input workflow name."""
|
54
|
-
try:
|
55
|
-
workflow: Workflow = Workflow.from_loader(name=name, externals={})
|
56
|
-
except ValueError as err:
|
57
|
-
logger.exception(err)
|
58
|
-
raise HTTPException(
|
59
|
-
status_code=st.HTTP_404_NOT_FOUND,
|
60
|
-
detail=(
|
61
|
-
f"Workflow workflow name: {name!r} does not found in /conf path"
|
62
|
-
),
|
63
|
-
) from None
|
64
|
-
return workflow.model_dump(
|
65
|
-
by_alias=True,
|
66
|
-
exclude_none=True,
|
67
|
-
exclude_unset=True,
|
68
|
-
exclude_defaults=True,
|
69
|
-
)
|
70
|
-
|
71
|
-
|
72
|
-
class ExecutePayload(BaseModel):
|
73
|
-
params: dict[str, Any]
|
74
|
-
|
75
|
-
|
76
|
-
@workflow_route.post(path="/{name}/execute", status_code=st.HTTP_202_ACCEPTED)
|
77
|
-
async def execute_workflow(name: str, payload: ExecutePayload) -> DictData:
|
78
|
-
"""Return model of workflow that passing an input workflow name."""
|
79
|
-
try:
|
80
|
-
workflow: Workflow = Workflow.from_loader(name=name, externals={})
|
81
|
-
except ValueError:
|
82
|
-
raise HTTPException(
|
83
|
-
status_code=st.HTTP_404_NOT_FOUND,
|
84
|
-
detail=(
|
85
|
-
f"Workflow workflow name: {name!r} does not found in /conf path"
|
86
|
-
),
|
87
|
-
) from None
|
88
|
-
|
89
|
-
# NOTE: Start execute manually
|
90
|
-
try:
|
91
|
-
result: Result = workflow.execute(params=payload.params)
|
92
|
-
except Exception as err:
|
93
|
-
raise HTTPException(
|
94
|
-
status_code=st.HTTP_500_INTERNAL_SERVER_ERROR,
|
95
|
-
detail=f"{type(err)}: {err}",
|
96
|
-
) from None
|
97
|
-
|
98
|
-
return asdict(result)
|
99
|
-
|
100
|
-
|
101
|
-
@workflow_route.get(path="/{name}/logs")
|
102
|
-
async def get_workflow_logs(name: str):
|
103
|
-
try:
|
104
|
-
return {
|
105
|
-
"message": f"Getting workflow {name!r} logs",
|
106
|
-
"logs": [
|
107
|
-
log.model_dump(
|
108
|
-
by_alias=True,
|
109
|
-
exclude_none=True,
|
110
|
-
exclude_unset=True,
|
111
|
-
exclude_defaults=True,
|
112
|
-
)
|
113
|
-
for log in get_audit().find_logs(name=name)
|
114
|
-
],
|
115
|
-
}
|
116
|
-
except FileNotFoundError:
|
117
|
-
raise HTTPException(
|
118
|
-
status_code=st.HTTP_404_NOT_FOUND,
|
119
|
-
detail=f"Does not found log for workflow {name!r}",
|
120
|
-
) from None
|
121
|
-
|
122
|
-
|
123
|
-
@workflow_route.get(path="/{name}/logs/{release}")
|
124
|
-
async def get_workflow_release_log(name: str, release: str):
|
125
|
-
try:
|
126
|
-
log: Audit = get_audit().find_log_with_release(
|
127
|
-
name=name, release=datetime.strptime(release, "%Y%m%d%H%M%S")
|
128
|
-
)
|
129
|
-
except FileNotFoundError:
|
130
|
-
raise HTTPException(
|
131
|
-
status_code=st.HTTP_404_NOT_FOUND,
|
132
|
-
detail=(
|
133
|
-
f"Does not found log for workflow {name!r} "
|
134
|
-
f"with release {release!r}"
|
135
|
-
),
|
136
|
-
) from None
|
137
|
-
return {
|
138
|
-
"message": f"Getting workflow {name!r} log in release {release}",
|
139
|
-
"log": log.model_dump(
|
140
|
-
by_alias=True,
|
141
|
-
exclude_none=True,
|
142
|
-
exclude_unset=True,
|
143
|
-
exclude_defaults=True,
|
144
|
-
),
|
145
|
-
}
|
146
|
-
|
147
|
-
|
148
|
-
@workflow_route.delete(
|
149
|
-
path="/{name}/logs/{release}",
|
150
|
-
status_code=st.HTTP_204_NO_CONTENT,
|
151
|
-
)
|
152
|
-
async def del_workflow_release_log(name: str, release: str):
|
153
|
-
return {"message": f"Deleted workflow {name!r} log in release {release}"}
|
154
|
-
|
155
|
-
|
156
27
|
@schedule_route.get(path="/{name}")
|
157
28
|
async def get_schedules(name: str):
|
158
29
|
try:
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# ------------------------------------------------------------------------------
|
2
|
+
# Copyright (c) 2022 Korawich Anuttra. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See LICENSE in the project root for
|
4
|
+
# license information.
|
5
|
+
# ------------------------------------------------------------------------------
|
6
|
+
from __future__ import annotations
|
7
|
+
|
8
|
+
from dataclasses import asdict
|
9
|
+
from datetime import datetime
|
10
|
+
from typing import Any
|
11
|
+
|
12
|
+
from fastapi import APIRouter, HTTPException
|
13
|
+
from fastapi import status as st
|
14
|
+
from fastapi.responses import UJSONResponse
|
15
|
+
from pydantic import BaseModel
|
16
|
+
|
17
|
+
from ...__types import DictData
|
18
|
+
from ...audit import Audit, get_audit
|
19
|
+
from ...conf import Loader, get_logger
|
20
|
+
from ...result import Result
|
21
|
+
from ...workflow import Workflow
|
22
|
+
|
23
|
+
logger = get_logger("ddeutil.workflow")
|
24
|
+
|
25
|
+
workflow_route = APIRouter(
|
26
|
+
prefix="/workflows",
|
27
|
+
tags=["workflows"],
|
28
|
+
default_response_class=UJSONResponse,
|
29
|
+
)
|
30
|
+
|
31
|
+
|
32
|
+
@workflow_route.get(path="/")
|
33
|
+
async def get_workflows() -> DictData:
|
34
|
+
"""Return all workflow workflows that exists in config path."""
|
35
|
+
workflows: DictData = dict(Loader.finds(Workflow))
|
36
|
+
return {
|
37
|
+
"message": f"Getting all workflows: {len(workflows)}",
|
38
|
+
"count": len(workflows),
|
39
|
+
"workflows": workflows,
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
@workflow_route.get(path="/{name}")
|
44
|
+
async def get_workflow_by_name(name: str) -> DictData:
|
45
|
+
"""Return model of workflow that passing an input workflow name."""
|
46
|
+
try:
|
47
|
+
workflow: Workflow = Workflow.from_loader(name=name, externals={})
|
48
|
+
except ValueError as err:
|
49
|
+
logger.exception(err)
|
50
|
+
raise HTTPException(
|
51
|
+
status_code=st.HTTP_404_NOT_FOUND,
|
52
|
+
detail=(
|
53
|
+
f"Workflow workflow name: {name!r} does not found in /conf path"
|
54
|
+
),
|
55
|
+
) from None
|
56
|
+
return workflow.model_dump(
|
57
|
+
by_alias=True,
|
58
|
+
exclude_none=True,
|
59
|
+
exclude_unset=True,
|
60
|
+
exclude_defaults=True,
|
61
|
+
)
|
62
|
+
|
63
|
+
|
64
|
+
class ExecutePayload(BaseModel):
|
65
|
+
params: dict[str, Any]
|
66
|
+
|
67
|
+
|
68
|
+
@workflow_route.post(path="/{name}/execute", status_code=st.HTTP_202_ACCEPTED)
|
69
|
+
async def execute_workflow(name: str, payload: ExecutePayload) -> DictData:
|
70
|
+
"""Return model of workflow that passing an input workflow name."""
|
71
|
+
try:
|
72
|
+
workflow: Workflow = Workflow.from_loader(name=name, externals={})
|
73
|
+
except ValueError:
|
74
|
+
raise HTTPException(
|
75
|
+
status_code=st.HTTP_404_NOT_FOUND,
|
76
|
+
detail=(
|
77
|
+
f"Workflow workflow name: {name!r} does not found in /conf path"
|
78
|
+
),
|
79
|
+
) from None
|
80
|
+
|
81
|
+
# NOTE: Start execute manually
|
82
|
+
try:
|
83
|
+
result: Result = workflow.execute(params=payload.params)
|
84
|
+
except Exception as err:
|
85
|
+
raise HTTPException(
|
86
|
+
status_code=st.HTTP_500_INTERNAL_SERVER_ERROR,
|
87
|
+
detail=f"{type(err)}: {err}",
|
88
|
+
) from None
|
89
|
+
|
90
|
+
return asdict(result)
|
91
|
+
|
92
|
+
|
93
|
+
@workflow_route.get(path="/{name}/audits")
|
94
|
+
async def get_workflow_audits(name: str):
|
95
|
+
try:
|
96
|
+
return {
|
97
|
+
"message": f"Getting workflow {name!r} audits",
|
98
|
+
"audits": [
|
99
|
+
audit.model_dump(
|
100
|
+
by_alias=True,
|
101
|
+
exclude_none=True,
|
102
|
+
exclude_unset=True,
|
103
|
+
exclude_defaults=True,
|
104
|
+
)
|
105
|
+
for audit in get_audit().find_audits(name=name)
|
106
|
+
],
|
107
|
+
}
|
108
|
+
except FileNotFoundError:
|
109
|
+
raise HTTPException(
|
110
|
+
status_code=st.HTTP_404_NOT_FOUND,
|
111
|
+
detail=f"Does not found audit for workflow {name!r}",
|
112
|
+
) from None
|
113
|
+
|
114
|
+
|
115
|
+
@workflow_route.get(path="/{name}/audits/{release}")
|
116
|
+
async def get_workflow_release_audit(name: str, release: str):
|
117
|
+
try:
|
118
|
+
audit: Audit = get_audit().find_audit_with_release(
|
119
|
+
name=name, release=datetime.strptime(release, "%Y%m%d%H%M%S")
|
120
|
+
)
|
121
|
+
except FileNotFoundError:
|
122
|
+
raise HTTPException(
|
123
|
+
status_code=st.HTTP_404_NOT_FOUND,
|
124
|
+
detail=(
|
125
|
+
f"Does not found audit for workflow {name!r} "
|
126
|
+
f"with release {release!r}"
|
127
|
+
),
|
128
|
+
) from None
|
129
|
+
return {
|
130
|
+
"message": f"Getting workflow {name!r} audit in release {release}",
|
131
|
+
"audit": audit.model_dump(
|
132
|
+
by_alias=True,
|
133
|
+
exclude_none=True,
|
134
|
+
exclude_unset=True,
|
135
|
+
exclude_defaults=True,
|
136
|
+
),
|
137
|
+
}
|
ddeutil/workflow/audit.py
CHANGED
@@ -12,16 +12,15 @@ from abc import ABC, abstractmethod
|
|
12
12
|
from collections.abc import Iterator
|
13
13
|
from datetime import datetime
|
14
14
|
from pathlib import Path
|
15
|
-
from typing import
|
15
|
+
from typing import ClassVar, Optional, Union
|
16
16
|
|
17
17
|
from pydantic import BaseModel, Field
|
18
18
|
from pydantic.functional_validators import model_validator
|
19
19
|
from typing_extensions import Self
|
20
20
|
|
21
21
|
from .__types import DictData, TupleStr
|
22
|
-
from .conf import config
|
23
|
-
|
24
|
-
logger = get_logger("ddeutil.workflow")
|
22
|
+
from .conf import config
|
23
|
+
from .logs import TraceLog, get_trace
|
25
24
|
|
26
25
|
__all__: TupleStr = (
|
27
26
|
"get_audit",
|
@@ -55,7 +54,7 @@ class BaseAudit(BaseModel, ABC):
|
|
55
54
|
|
56
55
|
:rtype: Self
|
57
56
|
"""
|
58
|
-
if config.
|
57
|
+
if config.enable_write_audit:
|
59
58
|
self.do_before()
|
60
59
|
return self
|
61
60
|
|
@@ -83,8 +82,8 @@ class FileAudit(BaseAudit):
|
|
83
82
|
self.pointer().mkdir(parents=True, exist_ok=True)
|
84
83
|
|
85
84
|
@classmethod
|
86
|
-
def
|
87
|
-
"""Generate the
|
85
|
+
def find_audits(cls, name: str) -> Iterator[Self]:
|
86
|
+
"""Generate the audit data that found from logs path with specific a
|
88
87
|
workflow name.
|
89
88
|
|
90
89
|
:param name: A workflow name that want to search release logging data.
|
@@ -100,12 +99,12 @@ class FileAudit(BaseAudit):
|
|
100
99
|
yield cls.model_validate(obj=json.load(f))
|
101
100
|
|
102
101
|
@classmethod
|
103
|
-
def
|
102
|
+
def find_audit_with_release(
|
104
103
|
cls,
|
105
104
|
name: str,
|
106
105
|
release: datetime | None = None,
|
107
106
|
) -> Self:
|
108
|
-
"""Return the
|
107
|
+
"""Return the audit data that found from logs path with specific
|
109
108
|
workflow name and release values. If a release does not pass to an input
|
110
109
|
argument, it will return the latest release from the current log path.
|
111
110
|
|
@@ -147,7 +146,7 @@ class FileAudit(BaseAudit):
|
|
147
146
|
:return: Return False if the release log was not pointed or created.
|
148
147
|
"""
|
149
148
|
# NOTE: Return False if enable writing log flag does not set.
|
150
|
-
if not config.
|
149
|
+
if not config.enable_write_audit:
|
151
150
|
return False
|
152
151
|
|
153
152
|
# NOTE: create pointer path that use the same logic of pointer method.
|
@@ -175,14 +174,11 @@ class FileAudit(BaseAudit):
|
|
175
174
|
|
176
175
|
:rtype: Self
|
177
176
|
"""
|
178
|
-
|
177
|
+
trace: TraceLog = get_trace(self.run_id, self.parent_run_id)
|
179
178
|
|
180
179
|
# NOTE: Check environ variable was set for real writing.
|
181
|
-
if not config.
|
182
|
-
|
183
|
-
f"({cut_id(self.run_id)}) [LOG]: Skip writing log cause "
|
184
|
-
f"config was set"
|
185
|
-
)
|
180
|
+
if not config.enable_write_audit:
|
181
|
+
trace.debug("[LOG]: Skip writing log cause config was set")
|
186
182
|
return self
|
187
183
|
|
188
184
|
log_file: Path = self.pointer() / f"{self.run_id}.log"
|
@@ -200,34 +196,29 @@ class FileAudit(BaseAudit):
|
|
200
196
|
class SQLiteAudit(BaseAudit): # pragma: no cov
|
201
197
|
"""SQLite Audit Pydantic Model."""
|
202
198
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
""",
|
217
|
-
}
|
199
|
+
table_name: ClassVar[str] = "workflow_log"
|
200
|
+
schemas: ClassVar[
|
201
|
+
str
|
202
|
+
] = """
|
203
|
+
workflow str,
|
204
|
+
release int,
|
205
|
+
type str,
|
206
|
+
context json,
|
207
|
+
parent_run_id int,
|
208
|
+
run_id int,
|
209
|
+
update datetime
|
210
|
+
primary key ( run_id )
|
211
|
+
"""
|
218
212
|
|
219
213
|
def save(self, excluded: list[str] | None) -> SQLiteAudit:
|
220
214
|
"""Save logging data that receive a context data from a workflow
|
221
215
|
execution result.
|
222
216
|
"""
|
223
|
-
|
217
|
+
trace: TraceLog = get_trace(self.run_id, self.parent_run_id)
|
224
218
|
|
225
219
|
# NOTE: Check environ variable was set for real writing.
|
226
|
-
if not config.
|
227
|
-
|
228
|
-
f"({cut_id(self.run_id)}) [LOG]: Skip writing log cause "
|
229
|
-
f"config was set"
|
230
|
-
)
|
220
|
+
if not config.enable_write_audit:
|
221
|
+
trace.debug("[LOG]: Skip writing log cause config was set")
|
231
222
|
return self
|
232
223
|
|
233
224
|
raise NotImplementedError("SQLiteAudit does not implement yet.")
|