diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py3/twisted/logger/_flatten.py | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-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.py | 175 |
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) |