Class FloggerMetadataKey<T>
- java.lang.Object
-
- io.spine.logging.flogger.FloggerMetadataKey<T>
-
public class FloggerMetadataKey<T> extends Object
Key for logging semi-structured metadata values.Metadata keys can be used to provide log statements with strongly typed values which can be read and interpreted by logging backends or other logs related tools. This mechanism is intended for values with specific semantics and should not be seen as a replacement for logging arguments as part of a formatted log message.
Examples of where using
MetadataKeyis suitable are:- Logging a value with special semantics (e.g. values that are handled specially by the logger backend).
- Passing configuration to a specific logger backend to modify behaviour for individual log
statements or all log statements in a
ScopedLoggingContext. - Logging a structured value in many places with consistent formatting (e.g. so it can later be re-parsed by logs related tools).
If you just want to log an general "key value pair" in a small number of log statements, it is still better to just do something like
log("key=%s", value).Metadata keys are expected to be singleton constants, and should never be allocated at the log site itself. Even though they are expected to be singletons, comparing keys should be done via
equals()(rather than '==') since this will be safe in cases where non-singleton keys exist, and is just as fast if the keys are singletons.It is strongly recommended that any public
FloggerMetadataKeyinstances are defined aspublic static finalfields in a top-level or nested class, which does no logging. Ideally a separate class would be defined to hold only the keys, since this allows keys to be loaded very early in the loggingPlatformlifecycle without risking any static initialization issues.Custom subclasses of
MetadataKeywhich override either of the protectedemit(T, io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler)methods should take care to avoid calling any code which might trigger logging since this could lead to unexpected recusrion, especially if the key is being logged as part of aScopedLoggingContext. While there is protection against unbounded reentrant logging in Flogger, it is still best practice to avoid it where possible.Metadata keys are passed to a log statement via the
with()method, so it can aid readability to choose a name for the constant field which reads "fluently" as part of the log statement. For example:// Prefer this... logger.atInfo().with(FILE_LOGGING_FOR, user).log("User specific log message..."); // to... logger.atInfo().with(SET_LOGGING_TO_USER_FILE, user).log("User specific log message...");Logger backends can act upon metadata present in log statements to modify behavior. Any metadata entries that are not handled by a backend explicitly are, by default, rendered as part of the log statement in a default format.
Note that some metadata entries are handled before being processed by the backend (e.g. rate limiting), but a metadata entry remains present to record the that rate limiting was enabled.
- See Also:
- Original Java code of Google Flogger
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static interfaceFloggerMetadataKey.KeyValueHandlerCallback interface to handle additional contextualMetadatain log statements.
-
Constructor Summary
Constructors Modifier Constructor Description protectedFloggerMetadataKey(String label, Class<? extends T> clazz, boolean canRepeat)Constructor for custom key subclasses.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description booleancanRepeat()Whether this key can be used to set more than one value in the metadata.Tcast(Object value)Cast an arbitrary value to the type of this key.protected voidemit(T value, FloggerMetadataKey.KeyValueHandler kvh)Override this method to provide custom logic for emitting one or more key/value pairs for a given metadata value (callsafeEmit(Object,KeyValueHandler)from logging code to actually emit values).protected voidemitRepeated(Iterator<T> values, FloggerMetadataKey.KeyValueHandler kvh)Override this method to provide custom logic for emitting one or more key/value pairs for a sequence of metadata values (callsafeEmitRepeated(Iterator,KeyValueHandler)from logging code to actually emit values).booleanequals(Object obj)longgetBloomFilterMask()Returns a 64-bit bloom filter mask for this metadata key, usable by backend implementations to efficiently determine uniqueness of keys (e.g.StringgetLabel()Returns a short, human readable text label which will prefix the metadata in cases where it is formatted as part of the log message.inthashCode()static <T> FloggerMetadataKey<T>repeated(String label, Class<T> clazz)Creates a key for a repeated piece of metadata.voidsafeEmit(T value, FloggerMetadataKey.KeyValueHandler kvh)Emits one or more key/value pairs for the given metadata value.voidsafeEmitRepeated(Iterator<T> values, FloggerMetadataKey.KeyValueHandler kvh)Emits one or more key/value pairs for a sequence of repeated metadata values.static <T> FloggerMetadataKey<T>single(String label, Class<? extends T> clazz)Creates a key for a single piece of metadata.StringtoString()
-
-
-
Constructor Detail
-
FloggerMetadataKey
protected FloggerMetadataKey(String label, Class<? extends T> clazz, boolean canRepeat)
Constructor for custom key subclasses. Most use-cases will not require the use of custom keys, but occasionally it can be useful to create a specific subtype to control the formatting of values or to have a family of related keys with a common parent type.
-
-
Method Detail
-
single
public static <T> FloggerMetadataKey<T> single(String label, Class<? extends T> clazz)
Creates a key for a single piece of metadata. If metadata is set more than once using this key for the same log statement, the last set value will be the one used, and other values will be ignored (although callers should never rely on this behavior).Key instances behave like singletons, and two key instances with the same label will still be considered distinct. The recommended approach is to always assign
MetadataKeyinstances to static final constants.When calling from Kotlin, please give preference to
MetadataKeysKt.singleKey(). In Kotlin, there's no explicit difference between primitive and object classes. When compiling to JVM, it is resolved during the compilation. An accident passing of a potentially primitive class may lead to a runtime exception because metadata keys are used with generics.
-
repeated
public static <T> FloggerMetadataKey<T> repeated(String label, Class<T> clazz)
Creates a key for a repeated piece of metadata. If metadata is added more than once using this key for a log statement, all values will be retained as key/value pairs in the order they were added.Key instances behave like singletons, and two key instances with the same label will still be considered distinct. The recommended approach is to always assign
MetadataKeyinstances to static final constants.When calling from Kotlin, please give preference to
MetadataKeysKt.repeatedKey(). In Kotlin, there's no explicit difference between primitive and object classes. When compiling to JVM, it is resolved during the compilation. An accident passing of a potentially primitive class may lead to a runtime exception because metadata keys are used with generics.
-
getLabel
public final String getLabel()
Returns a short, human readable text label which will prefix the metadata in cases where it is formatted as part of the log message.
-
canRepeat
public final boolean canRepeat()
Whether this key can be used to set more than one value in the metadata.
-
safeEmit
public final void safeEmit(T value, FloggerMetadataKey.KeyValueHandler kvh)
Emits one or more key/value pairs for the given metadata value. Call this method in preference to usingemitRepeated(java.util.Iterator<T>, io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler)directly to protect against unbounded reentrant logging.
-
safeEmitRepeated
public final void safeEmitRepeated(Iterator<T> values, FloggerMetadataKey.KeyValueHandler kvh)
Emits one or more key/value pairs for a sequence of repeated metadata values. Call this method in preference to usingemitRepeated(java.util.Iterator<T>, io.spine.logging.flogger.FloggerMetadataKey.KeyValueHandler)directly to protect against unbounded reentrant logging.
-
emit
protected void emit(T value, FloggerMetadataKey.KeyValueHandler kvh)
Override this method to provide custom logic for emitting one or more key/value pairs for a given metadata value (callsafeEmit(Object,KeyValueHandler)from logging code to actually emit values).By default this method simply emits the given value with this key's label, but it can be customized key/value pairs if necessary.
Note that if multiple key/value pairs are emitted, the following best-practice should be followed:
- Key names should be of the form
"<label>.<suffix>". - Suffixes should only contain lower case ASCII letters and underscore (i.e. [a-z_]).
This method is called as part of logs processing and could be invoked a very large number of times in performance critical code. Implementations must be very careful to avoid calling any code which might risk deadlocks, stack overflow, concurrency issues or performance problems. In particular, implementations of this method should be careful to avoid:
- Calling any code which could log using the same
MetadataKeyinstance (unless you implement protection against reentrant calling in this method). - Calling code which might block (e.g. performing file I/O or acquiring locks).
- Allocating non-trivial amounds of memory (e.g. recording values in an unbounded data structure).
If you do implement a
MetadataKeywith non-trivial value processing, you should always make it very clear in the documentation that the key may not be suitable for widespread use.By default this method just calls
out.handle(getLabel(), value). - Key names should be of the form
-
emitRepeated
protected void emitRepeated(Iterator<T> values, FloggerMetadataKey.KeyValueHandler kvh)
Override this method to provide custom logic for emitting one or more key/value pairs for a sequence of metadata values (callsafeEmitRepeated(Iterator,KeyValueHandler)from logging code to actually emit values).Emits one or more key/value pairs for a sequence of repeated metadata values. By default this method simply calls
emit(Object,KeyValueHandler)once for each value, in order. However it could be overridden to treat the sequence of values for a repeated key as a single entity (e.g. by joining elements with a separator).See the
emit(Object,KeyValueHandler)method for additional caveats for custom implementations.
-
getBloomFilterMask
public final long getBloomFilterMask()
Returns a 64-bit bloom filter mask for this metadata key, usable by backend implementations to efficiently determine uniqueness of keys (e.g. for deduplication and grouping). This value is calculated on the assumption that there are normally not more than 10 distinct metadata keys being processed at any time. If more distinct keys need to be processed using this Bloom Filter mask, it will result in a higher than optimal false-positive rate.
-
-