Skip to content

Commit 2c245f7

Browse files
authored
fix(cloud-logging): removing Logstash dependencies, using Cloud Logging Logback (#10274)
* refactor: migrate Logstash logging to MDC and Google Cloud Logging appender while updating dependencies and test configuration * build: removed Jacoco library override and skip for local testing, not neccesary for cloud test * fix: restore original System.out in AppTest teardown to prevent side effects on other tests * docs: add output_structured_log.md example for Cloud Run manual logging
1 parent 48c7d60 commit 2c245f7

5 files changed

Lines changed: 57 additions & 37 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<!-- [START cloudrun_manual_logging_output] -->
2+
{"severity":"INFO","time":"YYYY-MM-DDTHH:MM:SS.SSSZ","logging.googleapis.com/labels":{"component":"arbitrary-property","levelName":"INFO","loggerName":"com.example.cloudrun.App","levelValue":"20000"},"logging.googleapis.com/trace_sampled":false,"message":"This is the default display field."}
3+
<!-- [END cloudrun_manual_logging_output] -->

run/logging-manual/pom.xml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ limitations under the License.
2828
<maven.compiler.target>17</maven.compiler.target>
2929
</properties>
3030

31+
<dependencyManagement>
32+
<dependencies>
33+
<dependency>
34+
<groupId>com.google.cloud</groupId>
35+
<artifactId>libraries-bom</artifactId>
36+
<version>26.32.0</version>
37+
<type>pom</type>
38+
<scope>import</scope>
39+
</dependency>
40+
</dependencies>
41+
</dependencyManagement>
42+
3143
<dependencies>
3244
<dependency>
3345
<groupId>com.sparkjava</groupId>
@@ -40,9 +52,13 @@ limitations under the License.
4052
<version>2.0.12</version>
4153
</dependency>
4254
<dependency>
43-
<groupId>net.logstash.logback</groupId>
44-
<artifactId>logstash-logback-encoder</artifactId>
45-
<version>7.4</version>
55+
<groupId>com.google.cloud</groupId>
56+
<artifactId>google-cloud-logging-logback</artifactId>
57+
</dependency>
58+
<dependency>
59+
<groupId>ch.qos.logback</groupId>
60+
<artifactId>logback-core</artifactId>
61+
<version>1.4.14</version>
4662
</dependency>
4763
<dependency>
4864
<groupId>ch.qos.logback</groupId>

run/logging-manual/src/main/java/com/example/cloudrun/App.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.example.cloudrun;
1818

19-
import static net.logstash.logback.argument.StructuredArguments.kv;
2019
import static spark.Spark.get;
2120
import static spark.Spark.port;
2221

@@ -27,6 +26,7 @@
2726
import okhttp3.Response;
2827
import org.slf4j.Logger;
2928
import org.slf4j.LoggerFactory;
29+
import org.slf4j.MDC;
3030

3131
public class App {
3232

@@ -41,30 +41,27 @@ public static void main(String[] args) {
4141
"/",
4242
(req, res) -> {
4343
// [START cloudrun_manual_logging]
44-
// Build structured log messages as an object.
45-
Object globalLogFields = null;
46-
4744
// Add log correlation to nest all log messages beneath request log in Log Viewer.
4845
// TODO(developer): delete this code if you're creating a Cloud
4946
// Function and it is *NOT* triggered by HTTP.
5047
String traceHeader = req.headers("x-cloud-trace-context");
5148
if (traceHeader != null && project != null) {
5249
String trace = traceHeader.split("/")[0];
53-
globalLogFields =
54-
kv(
55-
"logging.googleapis.com/trace",
56-
String.format("projects/%s/traces/%s", project, trace));
50+
MDC.put(
51+
"logging.googleapis.com/trace",
52+
String.format("projects/%s/traces/%s", project, trace));
5753
}
5854
// -- End log correlation code --
5955

60-
// Create a structured log entry using key value pairs.
56+
// Create a structured log entry using MDC (Mapped Diagnostic Context) keys.
6157
// For instantiating the "logger" variable, see
6258
// https://cloud.google.com/run/docs/logging#run_manual_logging-java
63-
logger.error(
64-
"This is the default display field.",
65-
kv("component", "arbitrary-property"),
66-
kv("severity", "NOTICE"),
67-
globalLogFields);
59+
MDC.put("component", "arbitrary-property");
60+
61+
logger.info("This is the default display field.");
62+
63+
// Clear MDC at the end of the request to avoid resource leaks
64+
MDC.clear();
6865
// [END cloudrun_manual_logging]
6966
res.status(200);
7067
return "Hello Logger!";
Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!-- [START cloudrun_manual_logging_logback] -->
33
<configuration>
4-
<appender name="jsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
5-
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
6-
<!-- Ignore default logging fields -->
7-
<fieldNames>
8-
<timestamp>[ignore]</timestamp>
9-
<version>[ignore]</version>
10-
<logger>[ignore]</logger>
11-
<thread>[ignore]</thread>
12-
<level>[ignore]</level>
13-
<levelValue>[ignore]</levelValue>
14-
</fieldNames>
15-
</encoder>
4+
<appender name="CLOUD" class="com.google.cloud.logging.logback.LoggingAppender">
5+
<!-- Optional : filter logs at or above a level -->
6+
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
7+
<level>INFO</level>
8+
</filter>
9+
<log>application.log</log> <!-- Optional : default java.log -->
10+
<resourceType>gae_app</resourceType> <!-- Optional : default: auto-detected, fallback: global -->
11+
<enhancer>com.example.logging.logback.enhancers.ExampleEnhancer</enhancer> <!-- Optional -->
12+
<flushLevel>WARN</flushLevel> <!-- Optional : default ERROR -->
13+
<!-- Redirect logs to stdout in JSON format for Cloud Run to capture -->
14+
<redirectToStdout>true</redirectToStdout>
1615
</appender>
1716
<root level="INFO">
18-
<appender-ref ref="jsonConsoleAppender"/>
17+
<appender-ref ref="CLOUD"/>
1918
</root>
2019
</configuration>
21-
<!-- [END cloudrun_manual_logging_logback] -->
20+
<!-- [END cloudrun_manual_logging_logback] -->

run/logging-manual/src/test/java/com/example/cloudrun/AppTest.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,31 @@
3434

3535
public class AppTest {
3636

37-
private ByteArrayOutputStream bout;
38-
private PrintStream out;
37+
private static ByteArrayOutputStream bout;
38+
private static PrintStream out;
39+
private static PrintStream originalOut;
3940

4041
@BeforeClass
4142
public static void beforeClass() {
43+
originalOut = System.out;
44+
bout = new ByteArrayOutputStream();
45+
out = new PrintStream(bout);
46+
System.setOut(out);
47+
4248
App app = new App();
4349
app.main(new String[] {});
4450
awaitInitialization();
4551
}
4652

4753
@AfterClass
4854
public static void afterClass() {
55+
System.setOut(originalOut);
4956
stop();
5057
}
5158

5259
@Before
5360
public void setUp() {
54-
bout = new ByteArrayOutputStream();
55-
out = new PrintStream(bout);
56-
System.setOut(out);
61+
bout.reset();
5762
}
5863

5964
@Test
@@ -63,7 +68,7 @@ public void shouldSucceed() throws IOException {
6368
assertEquals("Hello Logger!", response.body);
6469
String output = bout.toString();
6570
assertTrue(output.toString().contains("This is the default display field."));
66-
assertTrue(output.toString().contains("NOTICE"));
71+
assertTrue(output.toString().contains("INFO"));
6772
assertTrue(output.toString().contains("arbitrary-property"));
6873
}
6974

0 commit comments

Comments
 (0)