Skip to content

Commit 69cb916

Browse files
ludochgae-java-bot
authored andcommitted
Remove SourceLocation from App Engine Java logging. It was used for Cloud Debugger tool that was shut down on May 31, 2023: https://docs.cloud.google.com/stackdriver/docs/deprecations/debugger-deprecation
PiperOrigin-RevId: 848655394 Change-Id: Ib9cd8211083beddf84e3c8e824e5c20797317b65
1 parent 00fc4e3 commit 69cb916

12 files changed

Lines changed: 17 additions & 599 deletions

File tree

protobuf/api/log_service.proto

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ syntax = "proto2";
2020

2121
package java.apphosting;
2222

23-
import "source.proto";
24-
2523
option java_package = "com.google.apphosting.api.logservice";
2624
option java_outer_classname = "LogServicePb";
2725

@@ -42,8 +40,6 @@ message UserAppLogLine {
4240
required int64 level = 2;
4341
required string message = 3;
4442

45-
// Line of code that generated this log message.
46-
optional SourceLocation source_location = 4;
4743
}
4844

4945
message UserAppLogGroup {
@@ -81,8 +77,6 @@ message LogLine {
8177
// User provided log message.
8278
required string log_message = 3;
8379

84-
// Line of code that generated this log message.
85-
optional SourceLocation source_location = 4;
8680
}
8781

8882
// Complete log information about a single request to an application.

protobuf/api/source.proto

Lines changed: 0 additions & 51 deletions
This file was deleted.

protobuf/app_logs.proto

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ syntax = "proto2";
1818

1919
package java.apphosting;
2020

21-
import "source.proto";
22-
2321
option cc_enable_arenas = true;
2422
option java_package = "com.google.apphosting.base.protos";
2523
option java_outer_classname = "AppLogsPb";
@@ -36,9 +34,6 @@ message AppLogLine {
3634

3735
// Message generated by application with details.
3836
required string message = 3;
39-
40-
// Line of code that generated this log message.
41-
optional SourceLocation source_location = 4;
4237
}
4338

4439
// Application log group. All logs in this structure belong to the same
@@ -57,9 +52,6 @@ message AppLogMessage {
5752

5853
// Message generated by application with details.
5954
optional string log_message = 2;
60-
61-
// Line of code that generated this log message.
62-
optional SourceLocation source_location = 4;
6355
}
6456

6557
// Collection of log messages as stored in the level_X: columns in logs v2.

runtime/impl/src/main/java/com/google/apphosting/runtime/AppLogsWriter.java

Lines changed: 3 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,16 @@
2121
import com.google.apphosting.base.protos.AppLogsPb.AppLogGroup;
2222
import com.google.apphosting.base.protos.AppLogsPb.AppLogLine;
2323
import com.google.apphosting.base.protos.RuntimePb.UPResponse;
24-
import com.google.apphosting.base.protos.SourcePb.SourceLocation;
2524
import com.google.common.annotations.VisibleForTesting;
2625
import com.google.common.base.Stopwatch;
27-
import com.google.common.base.Throwables;
2826
import com.google.common.collect.ImmutableList;
2927
import com.google.common.flogger.GoogleLogger;
28+
import java.time.Duration;
3029
import java.util.ArrayList;
3130
import java.util.List;
3231
import java.util.concurrent.ExecutionException;
3332
import java.util.concurrent.Future;
3433
import java.util.logging.Level;
35-
import java.util.regex.Pattern;
3634
import javax.annotation.concurrent.GuardedBy;
3735

3836
/**
@@ -77,17 +75,6 @@ public class AppLogsWriter {
7775
static final String LOG_TRUNCATED_SUFFIX = "\n<truncated>";
7876
static final int LOG_TRUNCATED_SUFFIX_LENGTH = LOG_TRUNCATED_SUFFIX.length();
7977

80-
// This regular expression should match a leading prefix of all
81-
// sensitive class names that are to be disregarded for the purposes
82-
// of finding the log source location.
83-
private static final String PROTECTED_LOGS_CLASSES_REGEXP =
84-
"(com\\.google\\.apphosting\\.runtime\\.security"
85-
+ "|java\\.lang\\.reflect"
86-
+ "|java\\.lang\\.invoke"
87-
+ "|java\\.security"
88-
+ "|sun\\.reflect"
89-
+ ")\\..+";
90-
9178
private final Object lock = new Object();
9279

9380
private final int maxLogMessageLength;
@@ -105,8 +92,6 @@ public class AppLogsWriter {
10592
private Future<byte[]> currentFlush;
10693
@GuardedBy("lock")
10794
private Stopwatch stopwatch;
108-
private static final Pattern PROTECTED_LOGS_CLASSES =
109-
Pattern.compile(PROTECTED_LOGS_CLASSES_REGEXP);
11095

11196
public AppLogsWriter(
11297
MutableUpResponse upResponse,
@@ -192,14 +177,6 @@ public void addLogRecordAndMaybeFlush(ApiProxy.LogRecord fullRecord) {
192177
.setTimestampUsec(record.getTimestamp())
193178
.setMessage(record.getMessage());
194179

195-
StackTraceElement frame = stackFrameFor(record.getStackFrame(), record.getSourceLocation());
196-
if (frame != null) {
197-
SourceLocation sourceLocation = getSourceLocationProto(frame);
198-
if (sourceLocation != null) {
199-
logLineBuilder.setSourceLocation(sourceLocation);
200-
}
201-
}
202-
203180
appLogLines.add(logLineBuilder.build());
204181
}
205182

@@ -228,7 +205,8 @@ private void addLogLinesAndMaybeFlush(Iterable<AppLogLine> appLogLines) {
228205
currentByteCount += serializedSize;
229206
}
230207

231-
if (maxSecondsBetweenFlush > 0 && stopwatch.elapsed().getSeconds() >= maxSecondsBetweenFlush) {
208+
if (maxSecondsBetweenFlush > 0
209+
&& stopwatch.elapsed().compareTo(Duration.ofSeconds(maxSecondsBetweenFlush)) >= 0) {
232210
waitForCurrentFlushAndStartNewFlush();
233211
}
234212
}
@@ -398,69 +376,6 @@ long getByteCountBeforeFlushing() {
398376
return maxBytesToFlush;
399377
}
400378

401-
/**
402-
* Converts the stack trace stored in the Throwable into a SourceLocation
403-
* proto. Heuristics are applied to strip out non user code, such as the App
404-
* Engine logging infrastructure, and the servlet engine. Heuristics are also
405-
* employed to convert class paths into file names.
406-
*/
407-
@VisibleForTesting
408-
SourceLocation getSourceLocationProto(StackTraceElement sourceLocationFrame) {
409-
if (sourceLocationFrame == null || sourceLocationFrame.getFileName() == null) {
410-
return null;
411-
}
412-
return SourceLocation.newBuilder()
413-
.setFile(sourceLocationFrame.getFileName())
414-
.setLine(sourceLocationFrame.getLineNumber())
415-
.setFunctionName(
416-
sourceLocationFrame.getClassName() + "." + sourceLocationFrame.getMethodName())
417-
.build();
418-
}
419-
420-
/**
421-
* Rewrites the given StackTraceElement with a filename and line number found by looking through
422-
* the given Throwable for a frame that has the same class and method as the input
423-
* StackTraceElement. If the input frame already has source information then just return it
424-
* unchanged.
425-
*/
426-
private static StackTraceElement stackFrameFor(StackTraceElement frame, Throwable stack) {
427-
if (frame == null) {
428-
// No user-provided stack frame.
429-
if (stack == null) {
430-
return null;
431-
}
432-
return getTopUserStackFrame(Throwables.lazyStackTrace(stack));
433-
}
434-
435-
// If we have a user-provided file:line, use it.
436-
if (frame.getFileName() != null && frame.getLineNumber() > 0) {
437-
return frame;
438-
}
439-
440-
// We should have a Throwable given the preceding, but if for some reason we don't, avoid
441-
// throwing NullPointerException.
442-
if (stack == null) {
443-
return null;
444-
}
445-
446-
return findStackFrame(frame.getClassName(), frame.getMethodName(), stack);
447-
}
448-
449-
/** Searches for the stack frame where the Throwable matches the provided class and method. */
450-
static StackTraceElement findStackFrame(String className, String methodName, Throwable stack) {
451-
List<StackTraceElement> stackFrames = Throwables.lazyStackTrace(stack);
452-
for (StackTraceElement stackFrame : stackFrames) {
453-
if (className.equals(stackFrame.getClassName())
454-
&& methodName.equals(stackFrame.getMethodName())) {
455-
return stackFrame;
456-
}
457-
}
458-
459-
// No matching stack frame was found, return the top user frame, which should be
460-
// the one that called the log method.
461-
return AppLogsWriter.getTopUserStackFrame(stackFrames);
462-
}
463-
464379
/**
465380
* Converts from a Java Logging level to an App Engine logging level.
466381
* SEVERE maps to error, WARNING to warn, INFO to info, and all
@@ -484,33 +399,4 @@ public static ApiProxy.LogRecord.Level convertLogLevel(Level level) {
484399
}
485400
}
486401

487-
/**
488-
* Analyzes a stack trace and returns the topmost frame that contains user
489-
* code, so as to filter out App Engine logging and servlet infrastructure
490-
* and just return frames relevant to user code.
491-
*/
492-
public static StackTraceElement getTopUserStackFrame(List<StackTraceElement> stack) {
493-
// Find the top-most stack frame in code that belongs to the user.
494-
boolean loggerFrameEncountered = false; // Set on the first java.util.logging.Logger frame
495-
for (StackTraceElement element : stack) {
496-
if (isLoggerFrame(element.getClassName())) {
497-
loggerFrameEncountered = true;
498-
} else if (loggerFrameEncountered) {
499-
// Skip protected frames, e.g., mirrors.
500-
if (!isProtectedFrame(element.getClassName())) {
501-
return element;
502-
}
503-
}
504-
}
505-
return null;
506-
}
507-
508-
private static boolean isLoggerFrame(String cname) {
509-
return cname.equals("java.util.logging.Logger")
510-
|| cname.equals("com.google.devtools.cdbg.debuglets.java.GaeDynamicLogHelper");
511-
}
512-
513-
private static boolean isProtectedFrame(String cname) {
514-
return PROTECTED_LOGS_CLASSES.matcher(cname).lookingAt();
515-
}
516402
}

runtime/impl/src/main/java/com/google/apphosting/runtime/JsonLogHandler.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
/** A log handler that publishes log messages in a json format. */
3434
public final class JsonLogHandler extends LogHandler {
3535
private static final String TRACE_KEY = "\"logging.googleapis.com/trace\": ";
36-
private static final String SOURCE_LOCATION_KEY = "\"logging.googleapis.com/sourceLocation\": ";
3736
private static final String SPAN_KEY = "\"logging.googleapis.com/spanId\": ";
3837
private static final String DEBUG = "DEBUG";
3938
private static final String INFO = "INFO";
@@ -75,7 +74,6 @@ public void publish(LogRecord record) {
7574
appendTraceId(json);
7675
appendSpanId(json);
7776
appendSeverity(json, record);
78-
appendSourceLocation(json, record);
7977
appendMessage(json, record); // must be last, see appendMessage
8078
json.append("}");
8179
// We must output the log all at once (should only call println once per call to publish)
@@ -135,24 +133,6 @@ private static void appendSeverity(StringBuilder json, LogRecord record) {
135133
json.append("\"severity\": \"").append(levelToSeverity(record.getLevel())).append("\", ");
136134
}
137135

138-
private static void appendSourceLocation(StringBuilder json, LogRecord record) {
139-
if (record.getSourceClassName() != null && record.getSourceMethodName() != null) {
140-
StackTraceElement stackFrame =
141-
AppLogsWriter.findStackFrame(
142-
record.getSourceClassName(), record.getSourceMethodName(), new Throwable());
143-
String function = '"' + stackFrame.getClassName() + "." + stackFrame.getMethodName() + '"';
144-
json.append(SOURCE_LOCATION_KEY)
145-
.append('{')
146-
.append("\"function\": ")
147-
.append(function)
148-
.append(", \"file\": \"")
149-
.append(stackFrame.getFileName())
150-
.append("\", \"line\": \"")
151-
.append(stackFrame.getLineNumber())
152-
.append("\"}, ");
153-
}
154-
}
155-
156136
private static String levelToSeverity(Level level) {
157137
int intLevel = (level == null) ? 0 : level.intValue();
158138
switch (intLevel) {

runtime/impl/src/main/java/com/google/apphosting/runtime/NullSandboxLogHandler.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,10 @@ public void publish(LogRecord record) {
5555
}
5656
}
5757

58-
private boolean logSourceLocationFor(LogRecord record) {
59-
// It is completely possible for the class or method name to be null, especially if the
60-
// LogRecord came from the form of Logger.logp that has explicit class and method name params.
61-
return record.getSourceClassName() != null && record.getSourceMethodName() != null;
62-
}
63-
6458
private ApiProxy.LogRecord convertLogRecord(LogRecord record, String message) {
6559
ApiProxy.LogRecord.Level level = AppLogsWriter.convertLogLevel(record.getLevel());
6660
long timestamp = record.getMillis() * 1000;
67-
if (logSourceLocationFor(record)) {
68-
StackTraceElement stackFrame = new StackTraceElement(
69-
record.getSourceClassName(), record.getSourceMethodName(), null, -1);
70-
return new ApiProxy.LogRecord(level, timestamp, message, stackFrame);
71-
} else {
72-
return new ApiProxy.LogRecord(level, timestamp, message);
73-
}
61+
return new ApiProxy.LogRecord(level, timestamp, message);
7462
}
7563

7664
@Override

0 commit comments

Comments
 (0)