aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Twisted/py3/twisted/logger/_flatten.py
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py3/twisted/logger/_flatten.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py3/twisted/logger/_flatten.py')
-rw-r--r--contrib/python/Twisted/py3/twisted/logger/_flatten.py175
1 files changed, 175 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py3/twisted/logger/_flatten.py b/contrib/python/Twisted/py3/twisted/logger/_flatten.py
new file mode 100644
index 0000000000..b79476aa24
--- /dev/null
+++ b/contrib/python/Twisted/py3/twisted/logger/_flatten.py
@@ -0,0 +1,175 @@
+# -*- test-case-name: twisted.logger.test.test_flatten -*-
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Code related to "flattening" events; that is, extracting a description of all
+relevant fields from the format string and persisting them for later
+examination.
+"""
+
+from collections import defaultdict
+from string import Formatter
+from typing import Any, Dict, Optional
+
+from ._interfaces import LogEvent
+
+aFormatter = Formatter()
+
+
+class KeyFlattener:
+ """
+ A L{KeyFlattener} computes keys for the things within curly braces in
+ PEP-3101-style format strings as parsed by L{string.Formatter.parse}.
+ """
+
+ def __init__(self) -> None:
+ """
+ Initialize a L{KeyFlattener}.
+ """
+ self.keys: Dict[str, int] = defaultdict(lambda: 0)
+
+ def flatKey(
+ self, fieldName: str, formatSpec: Optional[str], conversion: Optional[str]
+ ) -> str:
+ """
+ Compute a string key for a given field/format/conversion.
+
+ @param fieldName: A format field name.
+ @param formatSpec: A format spec.
+ @param conversion: A format field conversion type.
+
+ @return: A key specific to the given field, format and conversion, as
+ well as the occurrence of that combination within this
+ L{KeyFlattener}'s lifetime.
+ """
+ if formatSpec is None:
+ formatSpec = ""
+
+ if conversion is None:
+ conversion = ""
+
+ result = "{fieldName}!{conversion}:{formatSpec}".format(
+ fieldName=fieldName,
+ formatSpec=formatSpec,
+ conversion=conversion,
+ )
+ self.keys[result] += 1
+ n = self.keys[result]
+ if n != 1:
+ result += "/" + str(self.keys[result])
+ return result
+
+
+def flattenEvent(event: LogEvent) -> None:
+ """
+ Flatten the given event by pre-associating format fields with specific
+ objects and callable results in a L{dict} put into the C{"log_flattened"}
+ key in the event.
+
+ @param event: A logging event.
+ """
+ if event.get("log_format", None) is None:
+ return
+
+ if "log_flattened" in event:
+ fields = event["log_flattened"]
+ else:
+ fields = {}
+
+ keyFlattener = KeyFlattener()
+
+ for literalText, fieldName, formatSpec, conversion in aFormatter.parse(
+ event["log_format"]
+ ):
+ if fieldName is None:
+ continue
+
+ if conversion != "r":
+ conversion = "s"
+
+ flattenedKey = keyFlattener.flatKey(fieldName, formatSpec, conversion)
+ structuredKey = keyFlattener.flatKey(fieldName, formatSpec, "")
+
+ if flattenedKey in fields:
+ # We've already seen and handled this key
+ continue
+
+ if fieldName.endswith("()"):
+ fieldName = fieldName[:-2]
+ callit = True
+ else:
+ callit = False
+
+ field = aFormatter.get_field(fieldName, (), event)
+ fieldValue = field[0]
+
+ if conversion == "r":
+ conversionFunction = repr
+ else: # Above: if conversion is not "r", it's "s"
+ conversionFunction = str
+
+ if callit:
+ fieldValue = fieldValue()
+
+ flattenedValue = conversionFunction(fieldValue)
+ fields[flattenedKey] = flattenedValue
+ fields[structuredKey] = fieldValue
+
+ if fields:
+ event["log_flattened"] = fields
+
+
+def extractField(field: str, event: LogEvent) -> Any:
+ """
+ Extract a given format field from the given event.
+
+ @param field: A string describing a format field or log key. This is the
+ text that would normally fall between a pair of curly braces in a
+ format string: for example, C{"key[2].attribute"}. If a conversion is
+ specified (the thing after the C{"!"} character in a format field) then
+ the result will always be str.
+ @param event: A log event.
+
+ @return: A value extracted from the field.
+
+ @raise KeyError: if the field is not found in the given event.
+ """
+ keyFlattener = KeyFlattener()
+
+ [[literalText, fieldName, formatSpec, conversion]] = aFormatter.parse(
+ "{" + field + "}"
+ )
+
+ assert fieldName is not None
+
+ key = keyFlattener.flatKey(fieldName, formatSpec, conversion)
+
+ if "log_flattened" not in event:
+ flattenEvent(event)
+
+ return event["log_flattened"][key]
+
+
+def flatFormat(event: LogEvent) -> str:
+ """
+ Format an event which has been flattened with L{flattenEvent}.
+
+ @param event: A logging event.
+
+ @return: A formatted string.
+ """
+ fieldValues = event["log_flattened"]
+ keyFlattener = KeyFlattener()
+ s = []
+
+ for literalText, fieldName, formatSpec, conversion in aFormatter.parse(
+ event["log_format"]
+ ):
+ s.append(literalText)
+
+ if fieldName is not None:
+ key = keyFlattener.flatKey(fieldName, formatSpec, conversion or "s")
+ s.append(str(fieldValues[key]))
+
+ return "".join(s)