Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
*
* @param <API>
* the logging API provided by this logger.
*
* @see <a href="https://github.com/google/flogger/blob/cb9e836a897d36a78309ee8badf5cad4e6a2d3d8/api/src/main/java/com/google/common/flogger/AbstractLogger.java">
* Original Java code of Google Flogger</a>
*/
Expand Down Expand Up @@ -81,10 +82,12 @@ protected AbstractLogger(LoggerBackend backend) {

/**
* Returns a fluent logging API appropriate for the specified log level.
*
* <p>
* If a logger implementation determines that logging is definitely disabled at this point then
* this method is expected to return a "no-op" implementation of that logging API, which will
* result in all further calls made for the log statement to being silently ignored.
*
* <p>
* A simple implementation of this method in a concrete subclass might look like:
* <pre>{@code
Expand Down
20 changes: 20 additions & 0 deletions jvm/middleware/src/main/java/io/spine/logging/jvm/JvmApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
/**
* The basic logging API. An implementation of this API (or an extension of it) will be
* returned by any fluent logger and forms the basis of the fluent call chain.
*
* <p>
* In typical usage each method in the API, with the exception of the terminal {@code log()}
* statements, will carry out some simple task (which may involve modifying the context of the log
Expand Down Expand Up @@ -82,9 +83,11 @@ public interface JvmApi<API extends JvmApi<API>> {
* is emitted all the rate limiters are reset. In particular for {@code every(N)} this means that
* logs need not always be emitted at multiples of {@code N} if other rate limiters are active,
* though it will always be at least {@code N}.
*
* <p>
* When rate limiting is active, a {@code "skipped"} count is added to log statements to indicate
* how many logs were disallowed since the last log statement was emitted.
*
* <p>
* If this method is called multiple times for a single log statement, the last invocation will
* take precedence.
Expand All @@ -107,9 +110,11 @@ public interface JvmApi<API extends JvmApi<API>> {
* only be emitted once all rate limiters have reached their threshold, and when a log statement
* is emitted all the rate limiters are reset. In particular for {@code onAverageEvery(N)} this
* means that logs may occurs less frequently than one-in-N if other rate limiters are active.
*
* <p>
* When rate limiting is active, a {@code "skipped"} count is added to log statements to indicate
* how many logs were disallowed since the last log statement was emitted.
*
* <p>
* If this method is called multiple times for a single log statement, the last invocation will
* take precedence.
Expand All @@ -124,6 +129,7 @@ public interface JvmApi<API extends JvmApi<API>> {
* specified duration must not be negative, and it is expected, but not required, that it is
* constant. In the absence of any other rate limiting, this method always allows the first
* invocation of any log statement to be emitted.
*
* <p>
* Note that for performance reasons {@code atMostEvery()} is explicitly <em>not</em> intended to
* perform "proper" rate limiting to produce a limited average rate over many samples.
Expand All @@ -136,6 +142,7 @@ public interface JvmApi<API extends JvmApi<API>> {
* }</pre>
* where {@code currentTimestampNanos} is the timestamp of the current log statement and
* {@code lastTimestampNanos} is a time stamp of the last log statement that was emitted.
*
* <p>
* The effect of this is that when logging invocation is relatively infrequent, the period
* between emitted log statements can be higher than the specified duration. For example
Expand All @@ -145,6 +152,7 @@ public interface JvmApi<API extends JvmApi<API>> {
* }</pre>
* logging would occur after {@code 0s}, {@code 2.4s} and {@code 4.8s} (not {@code 4.2s}),
* giving an effective duration of {@code 2.4s} between log statements over time.
*
* <p>
* Providing a zero-length duration (i.e., {@code n == 0}) disables rate limiting and makes this
* method an effective no-op.
Expand All @@ -165,9 +173,11 @@ public interface JvmApi<API extends JvmApi<API>> {
* only be emitted once all rate limiters have reached their threshold, and when a log statement
* is emitted all the rate limiters are reset. So even if the rate limit duration has expired, it
* does not mean that logging will occur.
*
* <p>
* When rate limiting is active, a {@code "skipped"} count is added to log statements to indicate
* how many logs were disallowed since the last log statement was emitted.
*
* <p>
* If this method is called multiple times for a single log statement, the last invocation will
* take precedence.
Expand Down Expand Up @@ -341,6 +351,7 @@ public interface JvmApi<API extends JvmApi<API>> {
* @param key the metadata key (expected to be a static constant)
* @param value a value to be associated with the key in this log statement. Null values are
* allowed, but the effect is always a no-op
*
* @throws NullPointerException if the given key is null
* @see JvmMetadataKey
*/
Expand Down Expand Up @@ -431,6 +442,7 @@ public interface JvmApi<API extends JvmApi<API>> {
* 16 bits is a log statement index to distinguish multiple statements on the same line
* (this becomes important if line numbers are stripped from the class file and everything
* appears to be on the same line).
*
* @param sourceFileName Optional base name of the source file (this value is strictly for
* debugging and does not contribute to either equals() or hashCode() behavior).
*/
Expand All @@ -449,11 +461,13 @@ API withInjectedLogSite(
* logger.atFine().log("Message: %s", value);
* }
* }</pre>
*
* <p>
* Note that if logging is enabled for a log level, it does not always follow that the log
* statement will definitely be written to the backend (due to the effects of other methods in
* the fluent chain), but if this method returns {@code false} then it can safely be assumed that
* no logging will occur.
*
* <p>
* This method is unaffected by additional methods in the fluent chain and should only ever be
* invoked immediately after the level selector method. In other words, the expression:
Expand All @@ -466,6 +480,7 @@ API withInjectedLogSite(
* <p>By avoiding passing a separate {@code Level} at runtime to determine "loggability", this API
* makes it easier to coerce bytecode optimizers into doing "dead code" removal on sections
* guarded by this method.
*
* <p>
* If a proxy logger class is supplied for which:
* <pre>{@code logger.atFine()}</pre>
Expand All @@ -486,6 +501,7 @@ API withInjectedLogSite(
*
* @param message the message template string containing an argument placeholder for each element
* of {@code varargs}.
*
* @param varargs the non-null array of arguments to be formatted.
*/
void logVarargs(String message, @Nullable Object[] varargs);
Expand All @@ -497,6 +513,7 @@ API withInjectedLogSite(
* <pre>{@code
* logger.at(INFO).withCause(error).log();
* }</pre>
*
* <p>
* However, as it is good practice to give all log statements a meaningful log message, use of this
* method should be rare.
Expand All @@ -505,6 +522,7 @@ API withInjectedLogSite(

/**
* Logs the given literal string without interpreting any argument placeholders.
*
* <p>
* Important: This is intended only for use with hard-coded, literal strings which cannot
* contain user data. If you wish to log user-generated data, you should do something like:
Expand All @@ -524,6 +542,7 @@ API withInjectedLogSite(
* Logs a formatted representation of the given parameter, using the specified message template.
* The message string is expected to contain argument placeholder terms appropriate to the
* logger's choice of parser.
*
* <p>
* Note that printf-style loggers are always expected to accept the standard Java printf
* formatting characters (e.g. "%s", "%d", etc...) and all flags unless otherwise stated.
Expand Down Expand Up @@ -816,6 +835,7 @@ void log(

/**
* An implementation of {@link JvmApi} which does nothing and discards all parameters.
*
* <p>
* This class (or a subclass in the case of an extended API) should be returned whenever logging
* is definitely disabled (e.g. when the log level is too low).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@
/**
* A value type which representing the location of a single log statement. This class is similar to
* the {@code StackTraceElement} class but differs in one important respect.
*
* <p>
* A LogSite can be associated with a globally unique ID, which can identify a log statement more
* uniquely than a line number (it is possible to have multiple log statements appear to be on a
* single line, especially for obfuscated classes).
*
* <p>
* Log sites are intended to be injected into code automatically, typically via some form of
* bytecode rewriting. Each injection mechanism can have its own implementation of {@code LogSite}
* adapted to its needs.
*
* <p>
* As a fallback, for cases where no injection mechanism is configured, a log site based upon stack
* trace analysis is used. However, due to limitations in the information available from
Expand All @@ -60,6 +63,7 @@ public abstract class JvmLogSite implements LogSiteKey {
* injecting it via {@link JvmApi#withInjectedLogSite} which will suppress any further
* log site analysis for that log statement. This is also returned if stack trace analysis
* fails for any reason.
*
* <p>
* If a log statement does end up with invalid log site information, then any fluent logging
* methods which rely on being able to look up site-specific metadata will be disabled and
Expand Down Expand Up @@ -135,6 +139,7 @@ public final String toString() {

/**
* Creates a log site injected from constants held a class' constant pool.
*
* <p>
* Used for compile-time log site injection, and by the agent.
*
Expand All @@ -145,6 +150,7 @@ public final String toString() {
* 16 bits is a log statement index to distinguish multiple statements on the same line
* (this becomes important if line numbers are stripped from the class file and everything
* appears to be on the same line).
*
* @param sourceFileName Optional base name of the source file (this value is strictly for
* debugging and does not contribute to either equals() or hashCode() behavior).
*
Expand Down
12 changes: 12 additions & 0 deletions jvm/middleware/src/main/java/io/spine/logging/jvm/JvmLogSites.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public final class JvmLogSites {
* conjunction with the {@link JvmApi#withInjectedLogSite(JvmLogSite)} method to implement
* logging helper methods. In some platforms, log site determination may be unsupported, and in
* those cases this method will always return the {@link JvmLogSite#INVALID} instance.
*
* <p>
* For example (in {@code MyLoggingHelper}):
* <pre>{@code
Expand All @@ -53,34 +54,40 @@ public final class JvmLogSites {
* .logVarargs(message, args);
* }
* }</pre>
*
* <p>
* This method should be used for the simple cases where the class in which the logging occurs is
* a public logging API. If the log statement is in a different class (not the public logging API)
* and the {@code LogSite} instance needs to be passed through several layers, consider using
* {@link #logSite()} instead to avoid too much "magic" in your code.
*
* <p>
* You should also seek to ensure that any API used with this method "looks like a logging API".
* It's no good if a log entry contains a class and method name which doesn't correspond to
* anything the user can relate to. In particular, the API should probably always accept the log
* message or at least some of its parameters, and should always have methods with "log" in their
* names to make the connection clear.
*
* <p>
* It is very important to note that this method can be very slow, since determining the log site
* can involve stack trace analysis. It is only recommended that it is used for cases where
* logging is expected to occur (e.g. {@code INFO} level or above). Implementing a helper method
* for {@code FINE} logging is usually unnecessary (it doesn't normally need to follow any
* specific "best practice" behavior).
*
* <p>
* Note that even when log site determination is supported, it is not defined as to whether two
* invocations of this method on the same line of code will produce the same instance, equivalent
* instances or distinct instance. Thus you should never invoke this method twice in a single
* statement (and you should never need to).
*
* <p>
* Note that this method call may be replaced in compiled applications via bytecode manipulation
* or other mechanisms to improve performance.
*
* @param loggingApi the logging API to be identified as the source of log statements (this must
* appear somewhere on the stack above the point at which this method is called).
*
* @return the log site of the caller of the specified logging API,
* or {@link JvmLogSite#INVALID} if the logging API was not found.
*/
Expand All @@ -94,6 +101,7 @@ public static JvmLogSite callerOf(Class<?> loggingApi) {
* the {@link JvmApi#withInjectedLogSite(JvmLogSite)} method to implement logging helper
* methods. In some platforms, log site determination may be unsupported, and in those cases this
* method will always return the {@link JvmLogSite#INVALID} instance.
*
* <p>
* For example (in {@code MyLoggingHelper}):
* <pre>{@code
Expand All @@ -107,21 +115,25 @@ public static JvmLogSite callerOf(Class<?> loggingApi) {
* <pre>{@code
* MyLoggingHelper.logAndSomethingElse(logSite(), "message...");
* }</pre>
*
* <p>
* Because this method adds an additional parameter and exposes a Flogger specific type to the
* calling code, you should consider using {@link #callerOf(Class)} for simple logging
* utilities.
*
* <p>
* It is very important to note that this method can be very slow, since determining the log site
* can involve stack trace analysis. It is only recommended that it is used for cases where
* logging is expected to occur (e.g. {@code INFO} level or above). Implementing a helper method
* for {@code FINE} logging is usually unnecessary (it doesn't normally need to follow any
* specific "best practice" behavior).
*
* <p>
* Note that even when log site determination is supported, it is not defined as to whether two
* invocations of this method on the same line of code will produce the same instance, equivalent
* instances or distinct instance. Thus you should never invoke this method twice in a single
* statement (and you should never need to).
*
* <p>
* Note that this method call may be replaced in compiled applications via bytecode manipulation
* or other mechanisms to improve performance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ public String toString() {
*
* @param level
* the log level for this log statement.
*
* @param isForced
* whether to force this log statement (see {@link #wasForced()} for details).
*/
Expand All @@ -406,8 +407,10 @@ protected LogContext(Level level, boolean isForced) {
*
* @param level
* the log level for this log statement.
*
* @param isForced
* whether to force this log statement (see {@link #wasForced()} for details).
*
* @param timestampNanos
* the nanosecond timestamp for this log statement.
*/
Expand Down Expand Up @@ -524,6 +527,7 @@ public final Metadata getMetadata() {
*
* @param key
* the metadata key (see {@link LogData}).
*
* @param value
* the metadata value.
*/
Expand Down Expand Up @@ -628,6 +632,7 @@ protected final void removeMetadata(JvmMetadataKey<?> key) {
*
* @param logSiteKey
* used to lookup persistent, per log statement, state.
*
* @return true if logging should be attempted (usually based on rate limiter state).
*/
protected boolean postProcess(@Nullable LogSiteKey logSiteKey) {
Expand Down Expand Up @@ -703,6 +708,7 @@ protected boolean postProcess(@Nullable LogSiteKey logSiteKey) {
*
* @param status
* a rate limiting status, or {@code null} if the rate limiter was not active.
*
* @return whether logging will occur based on the current combined state of
* active rate limiters.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ protected LogPerBucketingStrategy(String name) {
*
* @param key
* a non-null key from a potentially unbounded set of log aggregation keys.
*
* @return 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
* {@code null} is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
*
* @param <V>
* The value type in the map.
*
* @see <a href="https://github.com/google/flogger/blob/cb9e836a897d36a78309ee8badf5cad4e6a2d3d8/api/src/main/java/com/google/common/flogger/LogSiteMap.java">
* Original Java code of Google Flogger</a>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public final class LogSiteStackTrace extends Exception {

/**
* Creates a synthetic exception to hold a call-stack generated for the log statement itself.
*
* <p>
* This exception is never expected to actually get thrown or caught at any point.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@
/**
* The default implementation of {@link AbstractLogger} which returns the basic {@link JvmApi}
* and uses the default parser and system configured backend.
*
* <p>
* Note that when extending the logging API or specifying a new parser, you will need to create a
* new logger class (rather than extending this one). Unlike the {@link LogContext} class,
* which must be extended in order to modify the logging API, this class is not generified and thus
* cannot be modified to produce a different logging API.
*
* <p>
* The choice to prevent direct extension of loggers was made deliberately to ensure that users of
* a specific logger implementation always get the same behavior.
Expand All @@ -52,6 +54,7 @@ public final class Middleman extends AbstractLogger<Middleman.Api> {
/**
* The non-wildcard, fully specified, logging API for this logger. Fluent logger implementations
* should specify a non-wildcard API like this with which to generify the abstract logger.
*
* <p>
* It is possible to add methods to this logger-specific API directly, but it is recommended that
* a separate top-level API and LogContext is created, allowing it to be shared by other
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
* final class CustomRateLimiter extends RateLimitStatus {
* private static final LogSiteMap<CustomRateLimiter> map =
* new LogSiteMap<CustomRateLimiter>() {
*
* @Override protected CustomRateLimiter initialValue() {
* return new CustomRateLimiter();
* }
Expand Down
Loading
Loading