json.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. """JSON formatter using the standard library's `json` for encoding.
  2. Module contains the `JsonFormatter` and a custom `JsonEncoder` which supports a greater
  3. variety of types.
  4. """
  5. ### IMPORTS
  6. ### ============================================================================
  7. ## Future
  8. from __future__ import annotations
  9. ## Standard Library
  10. import datetime
  11. import json
  12. from typing import Any
  13. from collections.abc import Callable
  14. import warnings
  15. ## Application
  16. from . import core
  17. from . import defaults as d
  18. ### CLASSES
  19. ### ============================================================================
  20. class JsonEncoder(json.JSONEncoder):
  21. """A custom encoder extending [json.JSONEncoder](https://docs.python.org/3/library/json.html#json.JSONEncoder)"""
  22. def default(self, o: Any) -> Any:
  23. if d.use_datetime_any(o):
  24. return self.format_datetime_obj(o)
  25. if d.use_exception_default(o):
  26. return d.exception_default(o)
  27. if d.use_traceback_default(o):
  28. return d.traceback_default(o)
  29. if d.use_enum_default(o):
  30. return d.enum_default(o)
  31. if d.use_bytes_default(o):
  32. return d.bytes_default(o)
  33. if d.use_dataclass_default(o):
  34. return d.dataclass_default(o)
  35. if d.use_type_default(o):
  36. return d.type_default(o)
  37. try:
  38. return super().default(o)
  39. except TypeError:
  40. return d.unknown_default(o)
  41. def format_datetime_obj(self, o: datetime.time | datetime.date | datetime.datetime) -> str:
  42. """Format datetime objects found in `self.default`
  43. This allows subclasses to change the datetime format without understanding the
  44. internals of the default method.
  45. """
  46. return d.datetime_any(o)
  47. class JsonFormatter(core.BaseJsonFormatter):
  48. """JSON formatter using the standard library's [`json`](https://docs.python.org/3/library/json.html) for encoding"""
  49. def __init__(
  50. self,
  51. *args,
  52. json_default: Callable | None = None,
  53. json_encoder: Callable | None = None,
  54. json_serializer: Callable = json.dumps,
  55. json_indent: int | str | None = None,
  56. json_ensure_ascii: bool = True,
  57. **kwargs,
  58. ) -> None:
  59. """
  60. Args:
  61. args: see [BaseJsonFormatter][pythonjsonlogger.core.BaseJsonFormatter]
  62. json_default: a function for encoding non-standard objects
  63. json_encoder: custom JSON encoder
  64. json_serializer: a [`json.dumps`](https://docs.python.org/3/library/json.html#json.dumps)-compatible callable
  65. that will be used to serialize the log record.
  66. json_indent: indent parameter for the `json_serializer`
  67. json_ensure_ascii: `ensure_ascii` parameter for the `json_serializer`
  68. kwargs: see [BaseJsonFormatter][pythonjsonlogger.core.BaseJsonFormatter]
  69. """
  70. super().__init__(*args, **kwargs)
  71. self.json_default = json_default
  72. self.json_encoder = json_encoder
  73. self.json_serializer = json_serializer
  74. self.json_indent = json_indent
  75. self.json_ensure_ascii = json_ensure_ascii
  76. if not self.json_encoder and not self.json_default:
  77. self.json_encoder = JsonEncoder
  78. return
  79. def jsonify_log_record(self, log_data: core.LogData) -> str:
  80. """Returns a json string of the log data."""
  81. return self.json_serializer(
  82. log_data,
  83. default=self.json_default,
  84. cls=self.json_encoder,
  85. indent=self.json_indent,
  86. ensure_ascii=self.json_ensure_ascii,
  87. )
  88. ### DEPRECATED COMPATIBILITY
  89. ### ============================================================================
  90. def __getattr__(name: str):
  91. if name == "RESERVED_ATTRS":
  92. warnings.warn(
  93. "RESERVED_ATTRS has been moved to pythonjsonlogger.core",
  94. DeprecationWarning,
  95. )
  96. return core.RESERVED_ATTRS
  97. raise AttributeError(f"module {__name__} has no attribute {name}")