Skip to content

Commit ba7fa40

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/add-tracking
2 parents bb65dbd + fafd902 commit ba7fa40

8 files changed

Lines changed: 555 additions & 272 deletions

File tree

.github/workflows/build.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ jobs:
2424
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
2525

2626
steps:
27-
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
27+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2828
with:
2929
submodules: recursive
3030

3131
- name: Install uv and set the python version
32-
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7
32+
uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7
3333
with:
3434
python-version: ${{ matrix.python-version }}
3535
activate-environment: true
@@ -57,9 +57,9 @@ jobs:
5757
runs-on: ubuntu-latest
5858

5959
steps:
60-
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
60+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
6161
- name: Install uv and set the python version
62-
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7
62+
uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7
6363
with:
6464
python-version: "3.13"
6565

@@ -76,18 +76,18 @@ jobs:
7676
contents: read
7777
security-events: write
7878
steps:
79-
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
79+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
8080
- name: Install uv and set the python version
81-
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7
81+
uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7
8282
with:
8383
python-version: "3.13"
8484
ignore-nothing-to-cache: true
8585

8686
- name: Initialize CodeQL
87-
uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4
87+
uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4
8888
with:
8989
languages: python
9090
config-file: ./.github/codeql-config.yml
9191

9292
- name: Perform CodeQL Analysis
93-
uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4
93+
uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ jobs:
4242
if: ${{ fromJSON(needs.release-please.outputs.release_created || false) }}
4343

4444
steps:
45-
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
45+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
4646

4747
- name: Install uv and set the python version
48-
uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7
48+
uses: astral-sh/setup-uv@e06108dd0aef18192324c70427afc47652e63a82 # v7
4949
with:
5050
python-version: "3.13"
5151

.pre-commit-config.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
default_stages: [pre-commit]
22
repos:
33
- repo: https://github.com/astral-sh/ruff-pre-commit
4-
rev: v0.14.3
4+
rev: v0.15.6
55
hooks:
66
- id: ruff-check
77
args: [--fix]
@@ -15,8 +15,13 @@ repos:
1515
- id: trailing-whitespace
1616
- id: check-merge-conflict
1717

18+
- repo: https://github.com/tox-dev/pyproject-fmt
19+
rev: v2.18.1
20+
hooks:
21+
- id: pyproject-fmt
22+
1823
- repo: https://github.com/pre-commit/mirrors-mypy
19-
rev: v1.18.2
24+
rev: v1.19.1
2025
hooks:
2126
- id: mypy
2227
files: openfeature|tests/typechecking

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,17 @@ Note that some providers may not support tracking; check the documentation for y
212212

213213
The OpenFeature SDK logs to the `openfeature` logger using the `logging` package from the Python Standard Library.
214214

215+
#### Logging Hook
216+
217+
The Python SDK includes a `LoggingHook`, which logs detailed information at key points during flag evaluation, using the `logging` package. This hook can be particularly helpful for troubleshooting and debugging; simply attach it at the global, client or invocation level and ensure your log level is set to "debug".
218+
219+
```python
220+
from openfeature import api
221+
from openfeature.hook.logging_hook import LoggingHook
222+
223+
api.add_hooks([LoggingHook()])
224+
```
225+
215226
### Domains
216227

217228
Clients can be assigned to a domain.

openfeature/hook/logging_hook.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import json
2+
import logging
3+
from dataclasses import asdict
4+
5+
from openfeature.evaluation_context import EvaluationContext
6+
from openfeature.exception import ErrorCode, OpenFeatureError
7+
from openfeature.flag_evaluation import FlagEvaluationDetails, FlagValueType
8+
from openfeature.hook import Hook, HookContext, HookHints
9+
10+
11+
class LoggingHook(Hook):
12+
def __init__(
13+
self,
14+
include_evaluation_context: bool = False,
15+
logger: logging.Logger | None = None,
16+
):
17+
self.logger = logger or logging.getLogger("openfeature")
18+
self.include_evaluation_context = include_evaluation_context
19+
20+
def _build_args(self, hook_context: HookContext, stage: str) -> dict:
21+
args = {
22+
"domain": hook_context.client_metadata.domain
23+
if hook_context.client_metadata
24+
else None,
25+
"provider_name": hook_context.provider_metadata.name
26+
if hook_context.provider_metadata
27+
else None,
28+
"flag_key": hook_context.flag_key,
29+
"default_value": hook_context.default_value,
30+
"stage": stage,
31+
}
32+
if self.include_evaluation_context:
33+
args["evaluation_context"] = json.dumps(
34+
asdict(hook_context.evaluation_context),
35+
default=str,
36+
)
37+
return args
38+
39+
def before(
40+
self, hook_context: HookContext, hints: HookHints
41+
) -> EvaluationContext | None:
42+
args = self._build_args(hook_context, "before")
43+
self.logger.debug("Flag evaluation %s", args)
44+
return None
45+
46+
def after(
47+
self,
48+
hook_context: HookContext,
49+
details: FlagEvaluationDetails[FlagValueType],
50+
hints: HookHints,
51+
) -> None:
52+
args = self._build_args(hook_context, "after")
53+
args["reason"] = details.reason
54+
args["variant"] = details.variant
55+
args["value"] = details.value
56+
self.logger.debug("Flag evaluation %s", args)
57+
58+
def error(
59+
self, hook_context: HookContext, exception: Exception, hints: HookHints
60+
) -> None:
61+
args = self._build_args(hook_context, "error")
62+
if isinstance(exception, OpenFeatureError):
63+
args["error_code"] = exception.error_code
64+
args["error_message"] = exception.error_message
65+
else:
66+
args["error_code"] = ErrorCode.GENERAL
67+
args["error_message"] = str(exception)
68+
self.logger.error("Flag evaluation %s", args)

0 commit comments

Comments
 (0)