Class LogPerBucketingStrategy<T>
- java.lang.Object
-
- com.google.common.flogger.LogPerBucketingStrategy<T>
-
public abstract class LogPerBucketingStrategy<T> extends Object
Provides a strategy for "bucketing" a potentially unbounded set of log aggregation keys used by theLoggingApi#per(T, LogPerBucketingStrategymethod.) When implementing new strategies not provided by this class, it is important to ensure that the
apply()method returns values from a bounded set of instances wherever possible.This is important because the returned values are held persistently for potentially many different log sites. If a different instance is returned each time
apply()is called, a different instance will be held in each log site. This multiplies the amount of memory that is retained indefinitely by any use ofLoggingApi#per(T,LogPerBucketingStrategy.) One way to handle arbitrary key types would be to create a strategy which "interns" instances in some way, to produce singleton identifiers. Unfortunately interning can itself be a cause of unbounded memory leaks, so a bucketing strategy wishing to perform interning should probably support a user defined maximum capacity to limit the overall risk. If too many instances are seen, the strategy should begin to return
null(and log an appropriate warning).The additional complexity created by this approach really tells us that types which require interning in order to be used as aggregation keys should be considered unsuitable, and callers should seek alternatives.
-
-
Constructor Summary
Constructors Modifier Constructor Description protectedLogPerBucketingStrategy(String name)Instantiates a strategy with the specified name (used for debugging).
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Concrete Methods Modifier and Type Method Description protected abstract @Nullable Objectapply(T key)Maps a log aggregation key from a potentially unbounded set of key values to a bounded set of instances.static LogPerBucketingStrategy<Object>byClass()A strategy which uses theClassof the given key for log aggregation.static LogPerBucketingStrategy<Object>byClassName()A strategy which uses theClassname of the given key for log aggregation.static LogPerBucketingStrategy<Object>byHashCode(int maxBuckets)A strategy which uses thehashCode()of a given key, modulomaxBuckets, for log aggregation.static LogPerBucketingStrategy<Object>forKnownKeys(Iterable<?> knownKeys)A strategy defined for some given set of known keys.static LogPerBucketingStrategy<Object>knownBounded()A strategy to use only if the set of log aggregation keys is known to be a strictly bounded set of instances with singleton semantics.StringtoString()
-
-
-
Constructor Detail
-
LogPerBucketingStrategy
protected LogPerBucketingStrategy(String name)
Instantiates a strategy with the specified name (used for debugging).
-
-
Method Detail
-
knownBounded
public static final LogPerBucketingStrategy<Object> knownBounded()
A strategy to use only if the set of log aggregation keys is known to be a strictly bounded set of instances with singleton semantics.WARNING: When using this strategy, keys passed to
LoggingApi#per(T,LogPerBucketingStrategyare used as-is by the log aggregation code, and held indefinitely by internal static data structures. As such it is vital that key instances used with this strategy have singleton semantics (i.e. if) k1.equals(k2)thenk1 == k2). Failure to adhere to this requirement is likely to result in hard to detect memory leaks.If keys do not have singleton semantics then you should use a different strategy, such as
byHashCode(int)orbyClass().
-
byClass
public static final LogPerBucketingStrategy<Object> byClass()
A strategy which uses theClassof the given key for log aggregation. This is useful when you need to aggregate over specific exceptions or similar type-distinguished instances.Note that using this strategy will result in a reference to the
Classobject of the key being retained indefinitely. This will prevent class unloading from occurring for affected classes, and it is up to the caller to decide if this is acceptable or not.
-
byClassName
public static final LogPerBucketingStrategy<Object> byClassName()
A strategy which uses theClassname of the given key for log aggregation. This is useful when you need to aggregate over specific exceptions or similar type-distinguished instances.This is an alternative strategy to
byClass()which avoids holding onto the class instance and avoids any issues with class unloading. However it may conflate classes if applications use complex arrangements of custom of class-loaders, but this should be extremely rare.
-
forKnownKeys
public static final LogPerBucketingStrategy<Object> forKnownKeys(Iterable<?> knownKeys)
A strategy defined for some given set of known keys.Unlike
knownBounded(), this strategy maps keys a bounded set of identifiers, and permits the use of non-singleton keys inLoggingApi#per(T,LogPerBucketingStrategy.) If keys outside this set are used this strategy returns
null, and log aggregation will not occur. Duplicates inknownKeysare ignored.
-
byHashCode
public static final LogPerBucketingStrategy<Object> byHashCode(int maxBuckets)
A strategy which uses thehashCode()of a given key, modulomaxBuckets, for log aggregation.This is a fallback strategy for cases where the set of possible values is not known in advance, or could be arbirarily large in unusual circumstances.
When using this method it is obviously important that the
hashCode()method of the expected keys is well distributed, since duplicate hash codes, or hash codes congruent tomaxBucketswill cause keys to be conflated.The caller is responsible for deciding the number of unique log aggregation keys this strategy can return. This choice is a trade-off between memory usage and the risk of conflating keys when performing log aggregation. Each log site using this strategy will hold up to
maxBucketsdistinct versions of log site information to allow rate limiting and other stateful operations to be applied separately per bucket. The overall allocation cost depends on the type of rate limiting used alongside this method, but it scales linearly withmaxBuckets.It is recommended to keep the value of
maxBucketsbelow 250, since this guarantees no additional allocations will occur when using this strategy, however the value chosen should be as small as practically possible for the typical expected number of unique keys.To avoid unwanted allocation at log sites, users are strongly encouraged to assign the returned value to a static field, and pass that to any log statements which need it.
-
apply
protected abstract @Nullable Object apply(T key)
Maps a log aggregation key from a potentially unbounded set of key values to a bounded set of instances.Implementations of this method should be efficient, and avoid allocating memory wherever possible. The returned value must be an immutable identifier with minimal additional allocation requirements and ideally have singleton semantics (e.g. an
EnumorIntegervalue).Warning: If keys are not known to have natural singleton semantics (e.g.
String) then returning the given key instance is generally a bad idea. Even if the set of key values is small, the set of distinct allocated instances passed toLoggingApi#per(T,LogPerBucketingStrategycan be unbounded, and that's what matters. As such it is always better to map keys to some singleton identifier or intern the keys in some way.) - Parameters:
key- a non-null key from a potentially unbounded set of log aggregation keys.- Returns:
- an immutable value from some known bounded set, which will be held persistently by
internal Flogger data structures as part of the log aggregation feature. If
nullis returned, the corresponding call toper(key, STRATEGY)has no effect.
-
-