1+ /*
2+ * Copyright 2025 Google LLC
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * https://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package com .google .showcase .v1beta1 .it .logging ;
18+
19+ import static com .google .common .truth .Truth .assertThat ;
20+
21+ import ch .qos .logback .classic .Level ;
22+ import ch .qos .logback .classic .spi .ILoggingEvent ;
23+ import com .google .api .gax .grpc .GrpcLoggingInterceptor ;
24+ import com .google .api .gax .httpjson .HttpJsonLoggingInterceptor ;
25+ import com .google .common .collect .ImmutableMap ;
26+ import com .google .showcase .v1beta1 .EchoClient ;
27+ import com .google .showcase .v1beta1 .EchoRequest ;
28+ import com .google .showcase .v1beta1 .EchoResponse ;
29+ import com .google .showcase .v1beta1 .it .util .TestClientInitializer ;
30+ import java .util .List ;
31+ import java .util .Map ;
32+ import java .util .concurrent .TimeUnit ;
33+ import org .junit .jupiter .api .AfterAll ;
34+ import org .junit .jupiter .api .BeforeAll ;
35+ import org .junit .jupiter .api .Test ;
36+ import org .slf4j .LoggerFactory ;
37+ import org .slf4j .event .KeyValuePair ;
38+
39+ // This test needs to run with GOOGLE_SDK_JAVA_LOGGING=true
40+ // mvn clean verify -P '!showcase,enable-integration-tests,loggingTestBase,slf4j2_logback'
41+ public class ITLogging {
42+ private static EchoClient grpcClient ;
43+
44+ private static EchoClient httpjsonClient ;
45+
46+ private static final KeyValuePair SERVICE_NAME_KEY_VALUE_PAIR =
47+ new KeyValuePair ("serviceName" , "google.showcase.v1beta1.Echo" );
48+ private static final KeyValuePair RPC_NAME_KEY_VALUE_PAIR =
49+ new KeyValuePair ("rpcName" , "google.showcase.v1beta1.Echo/Echo" );
50+ private static final KeyValuePair RESPONSE_STATUS_KEY_VALUE_PAIR =
51+ new KeyValuePair ("response.status" , "OK" );
52+ private static final KeyValuePair RESPONSE_STATUS_KEY_VALUE_PAIR_HTTP =
53+ new KeyValuePair ("response.status" , "200" );
54+ private static final KeyValuePair REQUEST_URL_KEY_VALUE_PAIR =
55+ new KeyValuePair ("request.url" , "http://localhost:7469" );
56+
57+ private static final KeyValuePair RESPONSE_HEADERS_KEY_VALUE_PAIR =
58+ new KeyValuePair ("response.headers" , ImmutableMap .of ("content-type" , "application/grpc" ));
59+
60+ private static final String SENDING_REQUEST_MESSAGE = "Sending request" ;
61+ private static final String RECEIVING_RESPONSE_MESSAGE = "Received response" ;
62+ private static final String ECHO_STRING = "echo?" ;
63+
64+ private TestAppender setupTestLogger (Class <?> clazz , Level level ) {
65+ TestAppender testAppender = new TestAppender ();
66+ testAppender .start ();
67+ org .slf4j .Logger logger = LoggerFactory .getLogger (clazz );
68+ ((ch .qos .logback .classic .Logger ) logger ).setLevel (level );
69+ ((ch .qos .logback .classic .Logger ) logger ).addAppender (testAppender );
70+ return testAppender ;
71+ }
72+
73+ @ BeforeAll
74+ static void createClients () throws Exception {
75+ // Create gRPC Echo Client
76+ grpcClient = TestClientInitializer .createGrpcEchoClient ();
77+ // Create Http JSON Echo Client
78+ httpjsonClient = TestClientInitializer .createHttpJsonEchoClient ();
79+ }
80+
81+ @ AfterAll
82+ static void destroyClients () throws InterruptedException {
83+ grpcClient .close ();
84+ httpjsonClient .close ();
85+
86+ grpcClient .awaitTermination (TestClientInitializer .AWAIT_TERMINATION_SECONDS , TimeUnit .SECONDS );
87+ httpjsonClient .awaitTermination (
88+ TestClientInitializer .AWAIT_TERMINATION_SECONDS , TimeUnit .SECONDS );
89+ }
90+
91+ @ Test
92+ void testGrpc_receiveContent_logDebug () {
93+ TestAppender testAppender = setupTestLogger (GrpcLoggingInterceptor .class , Level .DEBUG );
94+ assertThat (echoGrpc (ECHO_STRING )).isEqualTo (ECHO_STRING );
95+
96+ assertThat (testAppender .events .size ()).isEqualTo (2 );
97+ // logging event for request
98+ ILoggingEvent loggingEvent1 = testAppender .events .get (0 );
99+ assertThat (loggingEvent1 .getMessage ()).isEqualTo (SENDING_REQUEST_MESSAGE );
100+ assertThat (loggingEvent1 .getLevel ()).isEqualTo (Level .DEBUG );
101+ List <KeyValuePair > keyValuePairs = loggingEvent1 .getKeyValuePairs ();
102+ assertThat (keyValuePairs .size ()).isEqualTo (4 );
103+ assertThat (keyValuePairs ).containsAtLeast (SERVICE_NAME_KEY_VALUE_PAIR , RPC_NAME_KEY_VALUE_PAIR );
104+
105+ for (KeyValuePair kvp : keyValuePairs ) {
106+ if (kvp .key .equals ("request.payload" )) {
107+ Map payload = (Map ) kvp .value ;
108+ assertThat (payload .get ("content" )).isEqualTo (ECHO_STRING );
109+ assertThat (payload .get ("requestId" )).isNotNull ();
110+ assertThat (payload .get ("otherRequestId" )).isNotNull ();
111+ }
112+ if (kvp .key .equals ("request.headers" )) {
113+ Map headers = (Map ) kvp .value ;
114+ assertThat (headers ).containsKey ("x-goog-api-version" );
115+ assertThat (headers ).containsKey ("x-goog-api-client" );
116+ }
117+ }
118+
119+ // logging event for response
120+ ILoggingEvent loggingEvent2 = testAppender .events .get (1 );
121+ assertThat (loggingEvent2 .getMessage ()).isEqualTo (RECEIVING_RESPONSE_MESSAGE );
122+
123+ assertThat (loggingEvent2 .getLevel ()).isEqualTo (Level .DEBUG );
124+ List <KeyValuePair > keyValuePairs2 = loggingEvent2 .getKeyValuePairs ();
125+ assertThat (keyValuePairs2 .size ()).isEqualTo (5 );
126+ assertThat (keyValuePairs2 )
127+ .containsAtLeast (
128+ RESPONSE_STATUS_KEY_VALUE_PAIR ,
129+ RESPONSE_HEADERS_KEY_VALUE_PAIR ,
130+ SERVICE_NAME_KEY_VALUE_PAIR ,
131+ RPC_NAME_KEY_VALUE_PAIR );
132+ for (KeyValuePair kvp : keyValuePairs2 ) {
133+ if (kvp .key .equals ("response.payload" )) {
134+ Map payload = (Map ) kvp .value ;
135+ assertThat (payload .get ("content" )).isEqualTo (ECHO_STRING );
136+ assertThat (payload .get ("requestId" )).isNotNull ();
137+ assertThat (payload .get ("otherRequestId" )).isNotNull ();
138+ }
139+ }
140+ testAppender .stop ();
141+ }
142+
143+ @ Test
144+ void testGrpc_receiveContent_logInfo () {
145+ TestAppender testAppender = setupTestLogger (GrpcLoggingInterceptor .class , Level .INFO );
146+ assertThat (echoGrpc (ECHO_STRING )).isEqualTo (ECHO_STRING );
147+
148+ assertThat (testAppender .events .size ()).isEqualTo (2 );
149+ // logging event for request
150+ ILoggingEvent loggingEvent1 = testAppender .events .get (0 );
151+ assertThat (loggingEvent1 .getMessage ()).isEqualTo (SENDING_REQUEST_MESSAGE );
152+ assertThat (loggingEvent1 .getLevel ()).isEqualTo (Level .INFO );
153+ List <KeyValuePair > keyValuePairs = loggingEvent1 .getKeyValuePairs ();
154+ assertThat (keyValuePairs .size ()).isEqualTo (2 );
155+ assertThat (keyValuePairs ).containsAtLeast (SERVICE_NAME_KEY_VALUE_PAIR , RPC_NAME_KEY_VALUE_PAIR );
156+
157+ // logging event for response
158+ ILoggingEvent loggingEvent2 = testAppender .events .get (1 );
159+ assertThat (loggingEvent2 .getMessage ()).isEqualTo (RECEIVING_RESPONSE_MESSAGE );
160+
161+ assertThat (loggingEvent2 .getLevel ()).isEqualTo (Level .INFO );
162+ List <KeyValuePair > keyValuePairs2 = loggingEvent2 .getKeyValuePairs ();
163+ assertThat (keyValuePairs2 .size ()).isEqualTo (3 );
164+ assertThat (keyValuePairs2 )
165+ .containsAtLeast (
166+ RESPONSE_STATUS_KEY_VALUE_PAIR , SERVICE_NAME_KEY_VALUE_PAIR , RPC_NAME_KEY_VALUE_PAIR );
167+ testAppender .stop ();
168+ }
169+
170+ @ Test
171+ void testHttpJson_receiveContent_logDebug () {
172+ TestAppender testAppender = setupTestLogger (HttpJsonLoggingInterceptor .class , Level .DEBUG );
173+ assertThat (echoHttpJson (ECHO_STRING )).isEqualTo (ECHO_STRING );
174+ assertThat (testAppender .events .size ()).isEqualTo (2 );
175+ // logging event for request
176+ ILoggingEvent loggingEvent1 = testAppender .events .get (0 );
177+ assertThat (loggingEvent1 .getMessage ()).isEqualTo (SENDING_REQUEST_MESSAGE );
178+ assertThat (loggingEvent1 .getLevel ()).isEqualTo (Level .DEBUG );
179+ List <KeyValuePair > keyValuePairs = loggingEvent1 .getKeyValuePairs ();
180+ assertThat (keyValuePairs .size ()).isEqualTo (4 );
181+ assertThat (keyValuePairs ).contains (RPC_NAME_KEY_VALUE_PAIR );
182+ assertThat (keyValuePairs ).contains (REQUEST_URL_KEY_VALUE_PAIR );
183+
184+ for (KeyValuePair kvp : keyValuePairs ) {
185+ if (kvp .key .equals ("request.payload" )) {
186+ Map payload = (Map ) kvp .value ;
187+ assertThat (payload .get ("content" )).isEqualTo (ECHO_STRING );
188+ assertThat (payload .get ("requestId" )).isNotNull ();
189+ assertThat (payload .get ("otherRequestId" )).isNotNull ();
190+ }
191+ if (kvp .key .equals ("request.headers" )) {
192+ Map headers = (Map ) kvp .value ;
193+ assertThat (headers ).containsKey ("x-goog-api-version" );
194+ assertThat (headers ).containsKey ("x-goog-api-client" );
195+ }
196+ }
197+
198+ // logging event for response
199+ ILoggingEvent loggingEvent2 = testAppender .events .get (1 );
200+ assertThat (loggingEvent2 .getMessage ()).isEqualTo (RECEIVING_RESPONSE_MESSAGE );
201+
202+ assertThat (loggingEvent2 .getLevel ()).isEqualTo (Level .DEBUG );
203+ List <KeyValuePair > keyValuePairs2 = loggingEvent2 .getKeyValuePairs ();
204+ assertThat (keyValuePairs2 .size ()).isEqualTo (4 );
205+ assertThat (keyValuePairs2 )
206+ .containsAtLeast (RESPONSE_STATUS_KEY_VALUE_PAIR_HTTP , RPC_NAME_KEY_VALUE_PAIR );
207+ for (KeyValuePair kvp : keyValuePairs2 ) {
208+ if (kvp .key .equals ("response.payload" )) {
209+ Map payload = (Map ) kvp .value ;
210+ assertThat (payload .get ("content" )).isEqualTo (ECHO_STRING );
211+ assertThat (payload .get ("requestId" )).isNotNull ();
212+ assertThat (payload .get ("otherRequestId" )).isNotNull ();
213+ }
214+ if (kvp .key .equals ("response.headers" )) {
215+ Map headers = (Map ) kvp .value ;
216+ assertThat (headers .size ()).isEqualTo (11 );
217+ }
218+ }
219+ testAppender .stop ();
220+ }
221+
222+ @ Test
223+ void testHttpJson_receiveContent_logInfo () {
224+ TestAppender testAppender = setupTestLogger (HttpJsonLoggingInterceptor .class , Level .INFO );
225+ assertThat (echoHttpJson (ECHO_STRING )).isEqualTo (ECHO_STRING );
226+ assertThat (testAppender .events .size ()).isEqualTo (2 );
227+ // logging event for request
228+ ILoggingEvent loggingEvent1 = testAppender .events .get (0 );
229+ assertThat (loggingEvent1 .getMessage ()).isEqualTo (SENDING_REQUEST_MESSAGE );
230+ assertThat (loggingEvent1 .getLevel ()).isEqualTo (Level .INFO );
231+ List <KeyValuePair > keyValuePairs = loggingEvent1 .getKeyValuePairs ();
232+ assertThat (keyValuePairs .size ()).isEqualTo (2 );
233+ assertThat (keyValuePairs ).contains (RPC_NAME_KEY_VALUE_PAIR );
234+ assertThat (keyValuePairs ).contains (REQUEST_URL_KEY_VALUE_PAIR );
235+
236+ // logging event for response
237+ ILoggingEvent loggingEvent2 = testAppender .events .get (1 );
238+ assertThat (loggingEvent2 .getMessage ()).isEqualTo (RECEIVING_RESPONSE_MESSAGE );
239+
240+ assertThat (loggingEvent2 .getLevel ()).isEqualTo (Level .INFO );
241+ List <KeyValuePair > keyValuePairs2 = loggingEvent2 .getKeyValuePairs ();
242+ assertThat (keyValuePairs2 .size ()).isEqualTo (2 );
243+ assertThat (keyValuePairs2 )
244+ .containsAtLeast (RESPONSE_STATUS_KEY_VALUE_PAIR_HTTP , RPC_NAME_KEY_VALUE_PAIR );
245+ testAppender .stop ();
246+ }
247+
248+ private String echoGrpc (String value ) {
249+ EchoResponse response = grpcClient .echo (EchoRequest .newBuilder ().setContent (value ).build ());
250+ return response .getContent ();
251+ }
252+
253+ private String echoHttpJson (String value ) {
254+ EchoResponse response = httpjsonClient .echo (EchoRequest .newBuilder ().setContent (value ).build ());
255+ return response .getContent ();
256+ }
257+ }
0 commit comments