All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.appengine.repackaged.com.google.common.flogger.LogSite Maven / Gradle / Ivy

There is a newer version: 2.0.27
Show newest version
/*
 * Copyright (C) 2012 The Flogger Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.flogger;

import static com.google.common.flogger.util.Checks.checkNotNull;

import com.google.errorprone.annotations.CheckReturnValue;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * 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.
 * 

* 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). *

* 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. *

* 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 * {@code StackTraceElement}, this log site will not be unique if multiple log statements are on the * the same, or if line number information was stripped from the class file. */ @CheckReturnValue public abstract class LogSite implements LogSiteKey { /** A value used for line numbers when the true information is not available. */ public static final int UNKNOWN_LINE = 0; /** * An singleton LogSite instance used to indicate that valid log site information cannot be * determined. This can be used to indicate that log site information is not available by * injecting it via {@link LoggingApi#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. *

* 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 * essentially become "no ops". */ public static final LogSite INVALID = new LogSite() { @Override public String getClassName() { return ""; } @Override public String getMethodName() { return ""; } @Override public int getLineNumber() { return UNKNOWN_LINE; } @Override public String getFileName() { return null; } // No need to implement equals() or hashCode() for a singleton instance. }; /** Returns the name of the class containing the log statement. */ public abstract String getClassName(); /** Returns the name of the method containing the log statement. */ public abstract String getMethodName(); /** * Returns a valid line number for the log statement in the range 1 - 65535, or * {@link #UNKNOWN_LINE} if not known. *

* There is a limit of 16 bits for line numbers in a class. See * here * for more details. */ public abstract int getLineNumber(); /** * Returns the name of the class file containing the log statement (or null if not known). The * source file name is optional and strictly for debugging. * *

Normally this value (if present) is extracted from the SourceFile attribute of the class * file (see the JVM class * file format specification for more details). */ @NullableDecl public abstract String getFileName(); // Provide a common toString() implementation for only the public attributes. @Override public final String toString() { StringBuilder out = new StringBuilder() .append("LogSite{ class=") .append(getClassName()) .append(", method=") .append(getMethodName()) .append(", line=") .append(getLineNumber()); if (getFileName() != null) { out.append(", file=") .append(getFileName()); } return out.append(" }").toString(); } /** * Creates a log site injected from constants held a class' constant pool. *

* Used for compile-time log site injection, and by the agent. * * @param internalClassName Slash separated class name obtained from the class constant pool. * @param methodName Method name obtained from the class constant pool. * @param encodedLineNumber line number and per-line log statement index encoded as a single * 32-bit value. The low 16-bits is the line number (0 to 0xFFFF inclusive) and the high * 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). * * @deprecated this method is only be used for log-site injection and should not be called * directly. */ @Deprecated public static LogSite injectedLogSite( String internalClassName, String methodName, int encodedLineNumber, @NullableDecl String sourceFileName) { return new InjectedLogSite(internalClassName, methodName, encodedLineNumber, sourceFileName); } private static final class InjectedLogSite extends LogSite { /** Internal (slash-separated) fully qualified class name (eg, "com/example/Foo$Bar"). */ private final String internalClassName; /** Bare method name (no signature information). */ private final String methodName; private final int encodedLineNumber; @NullableDecl private final String sourceFileName; private int hashcode = 0; private InjectedLogSite( String internalClassName, String methodName, int encodedLineNumber, @NullableDecl String sourceFileName) { this.internalClassName = checkNotNull(internalClassName, "class name"); this.methodName = checkNotNull(methodName, "method name"); this.encodedLineNumber = encodedLineNumber; this.sourceFileName = sourceFileName; } @Override public String getClassName() { // We have to do the conversion from internal to public class name somewhere, and doing it // earlier could cost work in cases where the log statement is dropped. We could cache the // result somewhere, but in the default Fluent Logger backend, this method is actually only // called once anyway when constructing the LogRecord instance. return internalClassName.replace('/', '.'); } @Override public String getMethodName() { return methodName; } @Override public int getLineNumber() { // Strip additional "uniqueness" information from the upper 16 bits. return encodedLineNumber & 0xFFFF; } @Override @NullableDecl public String getFileName() { return sourceFileName; } @Override public boolean equals(Object obj) { if (obj instanceof InjectedLogSite) { InjectedLogSite other = (InjectedLogSite) obj; // Probably not worth optimizing for "this == obj" because all strings should be interned. return internalClassName.equals(other.internalClassName) && methodName.equals(other.methodName) && encodedLineNumber == other.encodedLineNumber; } return false; } @Override public int hashCode() { if (hashcode == 0) { // TODO(dbeaumont): Revisit the algorithm when looking at b/22753674. // If the log statement uses metadata, the log site will be used as a key to look up the // current value. In most cases the hashcode is never needed, but in others it may be used // multiple times in different data structures. int temp = 157; temp = 31 * temp + internalClassName.hashCode(); temp = 31 * temp + methodName.hashCode(); temp = 31 * temp + encodedLineNumber; hashcode = temp; } return hashcode; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy