Skip to content

Commit 848d4bb

Browse files
sebright2ahmetb
authored andcommitted
adservice: enable structured logging and OpenCensus log correlation (GoogleCloudPlatform#59)
This commit enables OpenCensus log correlation using opencensus-contrib-log-correlation-log4j2 (https://github.com/census-instrumentation/opencensus-java/tree/master/contrib/log_correlation/log4j2). The library inserts the trace ID, span ID, and sampling decision into every Log4j log event. This commit includes other changes to make the tracing data available in the logs, in a format that can be interpreted by the Stackdriver Logging agent: - Convert all adservice log statements from java.util.logging to Log4j. - Specify a JSON format for Log4j output. This is related to issue GoogleCloudPlatform#47. - Add the trace ID, span ID, and sampling decision to the JSON format. Trace ID and span ID use special keys that the Stackdriver Logging agent uses to populate the tracing data fields in the LogEntry uploaded to Stackdriver (https://cloud.google.com/logging/docs/agent/configuration#special_fields_in_structured_payloads). However, Stackdriver won't be able to link the traces and log entries until fluent-plugin-google-cloud can automatically format the trace ID with the format expected by Stackdriver (GoogleCloudPlatform/fluent-plugin-google-cloud#239, GoogleCloudPlatform/fluent-plugin-google-cloud#260). This commit also upgrades OpenCensus to 0.16.1 in order to use opencensus-contrib-log-correlation-log4j2.
1 parent dc7effd commit 848d4bb

4 files changed

Lines changed: 51 additions & 16 deletions

File tree

src/adservice/build.gradle

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ repositories {
2525
group = "adservice"
2626
version = "0.1.0-SNAPSHOT" // CURRENT_OPENCENSUS_VERSION
2727

28-
def opencensusVersion = "0.15.0" // LATEST_OPENCENSUS_RELEASE_VERSION
28+
def opencensusVersion = "0.16.1" // LATEST_OPENCENSUS_RELEASE_VERSION
2929
def grpcVersion = "1.15.0" // CURRENT_GRPC_VERSION
30+
def jacksonVersion = "2.9.6"
3031
def prometheusVersion = "0.3.0"
3132

3233
tasks.withType(JavaCompile) {
@@ -52,9 +53,13 @@ dependencies {
5253
"io.grpc:grpc-stub:${grpcVersion}",
5354
"io.grpc:grpc-netty:${grpcVersion}",
5455
"io.grpc:grpc-services:${grpcVersion}",
55-
"io.prometheus:simpleclient_httpserver:${prometheusVersion}"
56+
"io.prometheus:simpleclient_httpserver:${prometheusVersion}",
57+
"org.apache.logging.log4j:log4j-core:2.11.1"
5658

57-
runtime "io.opencensus:opencensus-impl:${opencensusVersion}",
59+
runtime "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}",
60+
"com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}",
61+
"io.opencensus:opencensus-contrib-log-correlation-log4j2:${opencensusVersion}",
62+
"io.opencensus:opencensus-impl:${opencensusVersion}",
5863
"io.netty:netty-tcnative-boringssl-static:2.0.8.Final"
5964
}
6065
}
@@ -106,13 +111,17 @@ task adService(type: CreateStartScripts) {
106111
applicationName = 'AdService'
107112
outputDir = new File(project.buildDir, 'tmp')
108113
classpath = jar.outputs.files + project.configurations.runtime
114+
defaultJvmOpts =
115+
["-Dlog4j2.contextDataInjector=io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector"]
109116
}
110117

111118
task adServiceClient(type: CreateStartScripts) {
112119
mainClassName = 'hipstershop.AdServiceClient'
113120
applicationName = 'AdServiceClient'
114121
outputDir = new File(project.buildDir, 'tmp')
115122
classpath = jar.outputs.files + project.configurations.runtime
123+
defaultJvmOpts =
124+
["-Dlog4j2.contextDataInjector=io.opencensus.contrib.logcorrelation.log4j2.OpenCensusTraceContextDataInjector"]
116125
}
117126

118127
applicationDistribution.into('bin') {

src/adservice/src/main/java/hipstershop/AdService.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@
5050
import java.util.List;
5151
import java.util.Random;
5252
import java.util.concurrent.TimeUnit;
53-
import java.util.logging.Level;
54-
import java.util.logging.Logger;
53+
import org.apache.logging.log4j.Level;
54+
import org.apache.logging.log4j.Logger;
55+
import org.apache.logging.log4j.LogManager;
5556

5657
public class AdService {
57-
private static final Logger logger = Logger.getLogger(AdService.class.getName());
58+
private static final Logger logger = LogManager.getLogger(AdService.class);
5859

5960
private static final Tracer tracer = Tracing.getTracer();
6061

@@ -139,7 +140,7 @@ public void getAds(AdRequest req, StreamObserver<AdResponse> responseObserver) {
139140
responseObserver.onNext(reply);
140141
responseObserver.onCompleted();
141142
} catch (StatusRuntimeException e) {
142-
logger.log(Level.WARNING, "GetAds Failed", e.getStatus());
143+
logger.log(Level.WARN, "GetAds Failed", e.getStatus());
143144
return;
144145
}
145146
}
@@ -218,15 +219,15 @@ public static void initStackdriver() {
218219
.build());
219220
} catch (Exception e) {
220221
if (i==(maxAttempts-1)) {
221-
logger.log(Level.WARNING, "Failed to register Stackdriver Exporter." +
222+
logger.log(Level.WARN, "Failed to register Stackdriver Exporter." +
222223
" Tracing and Stats data will not reported to Stackdriver. Error message: " + e
223224
.toString());
224225
} else {
225226
logger.info("Attempt to register Stackdriver Exporter in " + sleepTime + " seconds ");
226227
try {
227228
Thread.sleep(TimeUnit.SECONDS.toMillis(sleepTime));
228229
} catch (Exception se) {
229-
logger.log(Level.WARNING, "Exception while sleeping" + se.toString());
230+
logger.log(Level.WARN, "Exception while sleeping" + se.toString());
230231
}
231232
}
232233
}

src/adservice/src/main/java/hipstershop/AdServiceClient.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@
3838
import io.opencensus.trace.samplers.Samplers;
3939
import java.io.IOException;
4040
import java.util.concurrent.TimeUnit;
41-
import java.util.logging.Level;
42-
import java.util.logging.Logger;
4341
import javax.annotation.Nullable;
42+
import org.apache.logging.log4j.Level;
43+
import org.apache.logging.log4j.Logger;
44+
import org.apache.logging.log4j.LogManager;
4445

4546
/** A simple client that requests ads from the Ads Service. */
4647
public class AdServiceClient {
47-
private static final Logger logger = Logger.getLogger(AdServiceClient.class.getName());
48+
private static final Logger logger = LogManager.getLogger(AdServiceClient.class);
4849

4950
private static final Tracer tracer = Tracing.getTracer();
5051

@@ -90,7 +91,7 @@ public void getAds(String contextKey) {
9091
CanonicalCode.valueOf(e.getStatus().getCode().name())
9192
.toStatus()
9293
.withDescription(e.getMessage()));
93-
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
94+
logger.log(Level.WARN, "RPC failed: {0}", e.getStatus());
9495
return;
9596
}
9697
for(Ad ads: response.getAdsList()) {
@@ -104,7 +105,7 @@ static int getPortOrDefaultFromArgs(String[] args, int index, int defaultPort) {
104105
try {
105106
portNumber = Integer.parseInt(args[index]);
106107
} catch (NumberFormatException e) {
107-
logger.warning(
108+
logger.warn(
108109
String.format("Port %s is invalid, use default port %d.", args[index], defaultPort));
109110
}
110111
}
@@ -156,15 +157,15 @@ public static void main(String[] args) throws IOException, InterruptedException
156157
.build());
157158
} catch (Exception e) {
158159
if (i==(maxAttempts-1)) {
159-
logger.log(Level.WARNING, "Failed to register Stackdriver Exporter." +
160+
logger.log(Level.WARN, "Failed to register Stackdriver Exporter." +
160161
" Tracing and Stats data will not reported to Stackdriver. Error message: " + e
161162
.toString());
162163
} else {
163164
logger.info("Attempt to register Stackdriver Exporter in " + sleepTime + " seconds");
164165
try {
165166
Thread.sleep(TimeUnit.SECONDS.toMillis(sleepTime));
166167
} catch (Exception se) {
167-
logger.log(Level.WARNING, "Exception while sleeping" + e.toString());
168+
logger.log(Level.WARN, "Exception while sleeping" + e.toString());
168169
}
169170
}
170171
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration status="WARN">
3+
<Appenders>
4+
<Console name="STDOUT" target="SYSTEM_OUT">
5+
6+
<!-- This is a JSON format that can be read by the Stackdriver Logging agent. The trace and
7+
span IDs are interpreted by Stackdriver, and "traceSampled" is a custom field. -->
8+
<JsonLayout compact="true" eventEol="true">
9+
<KeyValuePair key="logging.googleapis.com/trace" value="$${ctx:opencensusTraceId}"/>
10+
<KeyValuePair key="logging.googleapis.com/spanId" value="$${ctx:opencensusSpanId}"/>
11+
<KeyValuePair key="traceSampled" value="$${ctx:opencensusTraceSampled}"/>
12+
</JsonLayout>
13+
14+
</Console>
15+
</Appenders>
16+
<Loggers>
17+
<Logger name="io.grpc.netty" level="INFO"/>
18+
<Logger name="io.netty" level="INFO"/>
19+
<Logger name="sun.net" level="INFO"/>
20+
<Root level="TRACE">
21+
<AppenderRef ref="STDOUT"/>
22+
</Root>
23+
</Loggers>
24+
</Configuration>

0 commit comments

Comments
 (0)