Skip to content

[core] Rename LogRecord/log_record to LogData/log_data #53

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: nhairs-str-to-object
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support `DictConfigurator` prefixes for `rename_fields` and `static_fields`. [#45](https://github.com/nhairs/python-json-logger/pull/45)
- Allows using values like `ext://sys.stderr` in `fileConfig`/`dictConfig` value fields.

### Changed
- Rename `pythonjsonlogger.core.LogRecord` and `log_record` arguemtns to avoid confusion / overlapping with `logging.LogRecord`. [#38](https://github.com/nhairs/python-json-logger/issues/38)
- Affects arguments to `pythonjsonlogger.core.BaseJsonFormatter` (and any child classes).
- `serialize_log_record`
- `add_fields`
- `jsonify_log_record`
- `process_log_record`
- Note: functions referring to `log_record` have **not** had their function name changed.

### Removed
- Remove support for providing strings instead of objects when instantiating formatters. Instead use the `DictConfigurator` `ext://` prefix format when using `fileConfig`/`dictConfig`. [#47](https://github.com/nhairs/python-json-logger/issues/47)
- Affects `pythonjsonlogger.json.JsonFormatter`: `json_default`, `json_encoder`, `json_serializer`.
Expand Down
10 changes: 5 additions & 5 deletions docs/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ You can modify the `dict` of data that will be logged by overriding the `process

```python
class SillyFormatter(JsonFormatter):
def process_log_record(log_record):
new_record = {k[::-1]: v for k, v in log_record.items()}
def process_log_record(log_data):
new_record = {k[::-1]: v for k, v in log_data.items()}
return new_record
```

Expand Down Expand Up @@ -119,9 +119,9 @@ Another method would be to create a custom formatter class and override the `pro
## -----------------------------------------------------------------------------
# Reuse REQUEST_ID stuff from solution 2
class MyFormatter(JsonFormatter):
def process_log_record(self, log_record):
log_record["request_id"] = get_request_id()
return log_record
def process_log_record(self, log_data):
log_data["request_id"] = get_request_id()
return log_data

handler.setFormatter(MyFormatter())

Expand Down
65 changes: 38 additions & 27 deletions src/pythonjsonlogger/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@

## Type Aliases
## -----------------------------------------------------------------------------
LogRecord: TypeAlias = Dict[str, Any]
"""Type alias"""
LogData: TypeAlias = Dict[str, Any]
"""Type alias

*Changed in 4.0*: renamed from `LogRecord` to `LogData`
"""


### FUNCTIONS
Expand Down Expand Up @@ -115,7 +118,7 @@ class BaseJsonFormatter(logging.Formatter):

*Changed in 3.2*: `defaults` argument is no longer ignored.

*Added in UNRELEASED*: `exc_info_as_array` and `stack_info_as_array` options are added.
*Added in 4.0*: `exc_info_as_array` and `stack_info_as_array` options are added.
"""

_style: Union[logging.PercentStyle, str] # type: ignore[assignment]
Expand Down Expand Up @@ -249,11 +252,11 @@ def format(self, record: logging.LogRecord) -> str:
if record.stack_info and not message_dict.get("stack_info"):
message_dict["stack_info"] = self.formatStack(record.stack_info)

log_record: LogRecord = {}
self.add_fields(log_record, record, message_dict)
log_record = self.process_log_record(log_record)
log_data: LogData = {}
self.add_fields(log_data, record, message_dict)
log_data = self.process_log_record(log_data)

return self.serialize_log_record(log_record)
return self.serialize_log_record(log_data)

## JSON Formatter Specific Methods
## -------------------------------------------------------------------------
Expand Down Expand Up @@ -287,17 +290,19 @@ def parse(self) -> List[str]:

return []

def serialize_log_record(self, log_record: LogRecord) -> str:
"""Returns the final representation of the log record.
def serialize_log_record(self, log_data: LogData) -> str:
"""Returns the final representation of the data to be logged

Args:
log_record: the log record
log_data: the data

*Changed in 4.0*: `log_record` renamed to `log_data`
"""
return self.prefix + self.jsonify_log_record(log_record)
return self.prefix + self.jsonify_log_record(log_data)

def add_fields(
self,
log_record: Dict[str, Any],
log_data: Dict[str, Any],
record: logging.LogRecord,
message_dict: Dict[str, Any],
) -> None:
Expand All @@ -306,65 +311,71 @@ def add_fields(
This method can be overridden to implement custom logic for adding fields.

Args:
log_record: data that will be logged
log_data: data that will be logged
record: the record to extract data from
message_dict: dictionary that was logged instead of a message. e.g
`logger.info({"is_this_message_dict": True})`

*Changed in 4.0*: `log_record` renamed to `log_data`
"""
for field in self.defaults:
log_record[self._get_rename(field)] = self.defaults[field]
log_data[self._get_rename(field)] = self.defaults[field]

for field in self._required_fields:
log_record[self._get_rename(field)] = record.__dict__.get(field)
log_data[self._get_rename(field)] = record.__dict__.get(field)

for data_dict in [self.static_fields, message_dict]:
for key, value in data_dict.items():
log_record[self._get_rename(key)] = value
log_data[self._get_rename(key)] = value

merge_record_extra(
record,
log_record,
log_data,
reserved=self._skip_fields,
rename_fields=self.rename_fields,
)

if self.timestamp:
key = self.timestamp if isinstance(self.timestamp, str) else "timestamp"
log_record[self._get_rename(key)] = datetime.fromtimestamp(
log_data[self._get_rename(key)] = datetime.fromtimestamp(
record.created, tz=timezone.utc
)

if self.rename_fields_keep_missing:
for field in self.rename_fields.values():
if field not in log_record:
log_record[field] = None
if field not in log_data:
log_data[field] = None
return

def _get_rename(self, key: str) -> str:
return self.rename_fields.get(key, key)

# Child Methods
# ..........................................................................
def jsonify_log_record(self, log_record: LogRecord) -> str:
"""Convert this log record into a JSON string.
def jsonify_log_record(self, log_data: LogData) -> str:
"""Convert the log data into a JSON string.

Child classes MUST override this method.

Args:
log_record: the data to serialize
log_data: the data to serialize

*Changed in 4.0*: `log_record` renamed to `log_data`
"""
raise NotImplementedError()

def process_log_record(self, log_record: LogRecord) -> LogRecord:
"""Custom processing of the log record.
def process_log_record(self, log_data: LogData) -> LogData:
"""Custom processing of the data to be logged.

Child classes can override this method to alter the log record before it
is serialized.

Args:
log_record: incoming data
log_data: incoming data

*Changed in 4.0*: `log_record` renamed to `log_data`
"""
return log_record
return log_data

def formatException(self, ei) -> Union[str, list[str]]: # type: ignore
"""Format and return the specified exception information.
Expand Down
6 changes: 3 additions & 3 deletions src/pythonjsonlogger/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ def __init__(
self.json_encoder = JsonEncoder
return

def jsonify_log_record(self, log_record: core.LogRecord) -> str:
"""Returns a json string of the log record."""
def jsonify_log_record(self, log_data: core.LogData) -> str:
"""Returns a json string of the log data."""
return self.json_serializer(
log_record,
log_data,
default=self.json_default,
cls=self.json_encoder,
indent=self.json_indent,
Expand Down
6 changes: 3 additions & 3 deletions src/pythonjsonlogger/msgspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ def __init__(
self._encoder = msgspec.json.Encoder(enc_hook=self.json_default)
return

def jsonify_log_record(self, log_record: core.LogRecord) -> str:
"""Returns a json string of the log record."""
return self._encoder.encode(log_record).decode("utf8")
def jsonify_log_record(self, log_data: core.LogData) -> str:
"""Returns a json string of the log data."""
return self._encoder.encode(log_data).decode("utf8")
6 changes: 3 additions & 3 deletions src/pythonjsonlogger/orjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ def __init__(
self.json_indent = json_indent
return

def jsonify_log_record(self, log_record: core.LogRecord) -> str:
"""Returns a json string of the log record."""
def jsonify_log_record(self, log_data: core.LogData) -> str:
"""Returns a json string of the log data."""
opt = orjson.OPT_NON_STR_KEYS
if self.json_indent:
opt |= orjson.OPT_INDENT_2

return orjson.dumps(log_record, default=self.json_default, option=opt).decode("utf8")
return orjson.dumps(log_data, default=self.json_default, option=opt).decode("utf8")
6 changes: 3 additions & 3 deletions tests/test_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,9 @@ def test_log_extra(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
def test_custom_logic_adds_field(env: LoggingEnvironment, class_: type[BaseJsonFormatter]):
class CustomJsonFormatter(class_): # type: ignore[valid-type,misc]

def process_log_record(self, log_record):
log_record["custom"] = "value"
return super().process_log_record(log_record)
def process_log_record(self, log_data):
log_data["custom"] = "value"
return super().process_log_record(log_data)

env.set_formatter(CustomJsonFormatter())
env.logger.info("message")
Expand Down