Skip to content

Commit 1699f70

Browse files
feat: Add support for partialSuccess (#908)
* feat: Add support for partialSuccess * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent bf2cced commit 1699f70

4 files changed

Lines changed: 89 additions & 12 deletions

File tree

.readme-partials.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ custom_content: |
4040
<!-- Optional: add custom labels to log entries using LoggingEnhancer classes -->
4141
<enhancer>com.example.enhancers.TestLoggingEnhancer</enhancer>
4242
<enhancer>com.example.enhancers.AnotherEnhancer</enhancer>
43+
44+
<!-- Optional: specifies if a batch's valid entries should be written even if some other entry failed due to an error. Defaults to true
45+
See [partial_success](https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write#body.request_body.FIELDS.partial_success) for more info -->
46+
<partialSuccess>true</partialSuccess>
4347
</appender>
4448
4549
<root level="info">

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ See [Logback filters](https://logback.qos.ch/manual/filters.html#thresholdFilter
111111
<!-- Optional: add custom labels to log entries using LoggingEnhancer classes -->
112112
<enhancer>com.example.enhancers.TestLoggingEnhancer</enhancer>
113113
<enhancer>com.example.enhancers.AnotherEnhancer</enhancer>
114+
115+
<!-- Optional: specifies if a batch's valid entries should be written even if some other entry failed due to an error. Defaults to true
116+
See [partial_success](https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write#body.request_body.FIELDS.partial_success) for more info -->
117+
<partialSuccess>true</partialSuccess>
114118
</appender>
115119

116120
<root level="info">

src/main/java/com/google/cloud/logging/logback/LoggingAppender.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
* &lt;!-- Optional: add custom labels to log entries using {@link LoggingEnhancer} classes --&gt;
8989
* &lt;enhancer&gt;com.example.enhancers.TestLoggingEnhancer&lt/enhancer&gt;
9090
* &lt;enhancer&gt;com.example.enhancers.AnotherEnhancer&lt/enhancer&gt;
91+
*
92+
* &lt;!-- Optional: specifies if a batch's valid entries should be written even if some other entry failed due to an error. Defaults to {@code true} --&gt;
93+
* &lt;partialSuccess&gt;true&lt;/partialSuccess&gt;
9194
* &lt;/appender&gt;
9295
* </pre>
9396
*/
@@ -118,6 +121,7 @@ public class LoggingAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
118121
private String logDestinationProjectId;
119122
private boolean autoPopulateMetadata = true;
120123
private boolean redirectToStdout = false;
124+
private boolean partialSuccess = true;
121125
private Synchronicity writeSyncFlag = Synchronicity.ASYNC;
122126
private final Set<String> enhancerClassNames = new HashSet<>();
123127
private final Set<String> loggingEventEnhancerClassNames = new HashSet<>();
@@ -214,6 +218,18 @@ public void setRedirectToStdout(boolean flag) {
214218
redirectToStdout = flag;
215219
}
216220

221+
/**
222+
* Sets the flag indicating if a batch's valid entries should be written even if some other entry
223+
* failed due to an error.
224+
*
225+
* <p>Default to {@code true}.
226+
*
227+
* @param flag the partialSuccess flag.
228+
*/
229+
public void setPartialSuccess(boolean flag) {
230+
partialSuccess = flag;
231+
}
232+
217233
/** Add extra labels using classes that implement {@link LoggingEnhancer}. */
218234
public void addEnhancer(String enhancerClassName) {
219235
this.enhancerClassNames.add(enhancerClassName);
@@ -298,7 +314,9 @@ public synchronized void start() {
298314

299315
defaultWriteOptions =
300316
new WriteOption[] {
301-
WriteOption.logName(getLogName()), WriteOption.resource(monitoredResource)
317+
WriteOption.logName(getLogName()),
318+
WriteOption.resource(monitoredResource),
319+
WriteOption.partialSuccess(partialSuccess)
302320
};
303321
Level flushLevel = getFlushLevel();
304322
if (flushLevel != Level.OFF) {

src/test/java/com/google/cloud/logging/logback/LoggingAppenderTest.java

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,19 @@ public void setUp() {
160160
new ImmutableMap.Builder<String, String>()
161161
.put("project_id", PROJECT_ID)
162162
.build())
163-
.build())
163+
.build()),
164+
WriteOption.partialSuccess(true),
164165
};
165166

166167
@Test
167168
public void testFlushLevelConfigUpdatesLoggingFlushSeverity() {
168169
logging.setFlushSeverity(Severity.WARNING);
169170
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
170171
logging.write(
171-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
172+
capture(capturedArgument),
173+
anyObject(WriteOption.class),
174+
anyObject(WriteOption.class),
175+
anyObject(WriteOption.class));
172176
replay(logging);
173177
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(100000, 0);
174178
LoggingEvent loggingEvent = createLoggingEvent(Level.WARN, timestamp.getSeconds());
@@ -194,7 +198,10 @@ public void testFilterLogsOnlyLogsAtOrAboveLogLevel() {
194198
logging.setFlushSeverity(Severity.ERROR);
195199
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
196200
logging.write(
197-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
201+
capture(capturedArgument),
202+
anyObject(WriteOption.class),
203+
anyObject(WriteOption.class),
204+
anyObject(WriteOption.class));
198205
expectLastCall().once();
199206
replay(logging);
200207
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(100000, 0);
@@ -215,12 +222,16 @@ public void testFilterLogsOnlyLogsAtOrAboveLogLevel() {
215222
}
216223

217224
@Test
218-
public void testDefaultWriteOptionsHasExpectedDefaults() {
225+
public void testPartialSuccessOverrideHasExpectedValue() {
219226
logging.setFlushSeverity(Severity.ERROR);
220227
Capture<WriteOption> logNameArg = Capture.newInstance();
221228
Capture<WriteOption> resourceArg = Capture.newInstance();
229+
Capture<WriteOption> partialSuccessArg = Capture.newInstance();
222230
logging.write(
223-
EasyMock.<Iterable<LogEntry>>anyObject(), capture(logNameArg), capture(resourceArg));
231+
EasyMock.<Iterable<LogEntry>>anyObject(),
232+
capture(logNameArg),
233+
capture(resourceArg),
234+
capture(partialSuccessArg));
224235
expectLastCall().once();
225236
replay(logging);
226237
loggingAppender.start();
@@ -231,14 +242,37 @@ public void testDefaultWriteOptionsHasExpectedDefaults() {
231242
assertThat(logNameArg.getValue()).isEqualTo(defaultWriteOptions[0]);
232243
// TODO(chingor): Fix this test to work on GCE and locally
233244
// assertThat(resourceArg.getValue()).isEqualTo(defaultWriteOptions[1]);
245+
assertThat(partialSuccessArg.getValue()).isEqualTo(defaultWriteOptions[2]);
246+
}
247+
248+
@Test
249+
public void testDefaultWriteOptionsHasExpectedDefaults() {
250+
logging.setFlushSeverity(Severity.ERROR);
251+
Capture<WriteOption> partialSuccessArg = Capture.newInstance();
252+
logging.write(
253+
EasyMock.<Iterable<LogEntry>>anyObject(),
254+
anyObject(WriteOption.class),
255+
anyObject(WriteOption.class),
256+
capture(partialSuccessArg));
257+
expectLastCall().once();
258+
replay(logging);
259+
loggingAppender.setPartialSuccess(false);
260+
loggingAppender.start();
261+
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(100000, 0);
262+
LoggingEvent loggingEvent = createLoggingEvent(Level.ERROR, timestamp.getSeconds());
263+
loggingAppender.doAppend(loggingEvent);
264+
assertThat(partialSuccessArg.getValue()).isEqualTo(WriteOption.partialSuccess(false));
234265
}
235266

236267
@Test
237268
public void testMdcValuesAreConvertedToLabels() {
238269
logging.setFlushSeverity(Severity.ERROR);
239270
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
240271
logging.write(
241-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
272+
capture(capturedArgument),
273+
anyObject(WriteOption.class),
274+
anyObject(WriteOption.class),
275+
anyObject(WriteOption.class));
242276
expectLastCall().once();
243277
replay(logging);
244278
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(100000, 0);
@@ -294,7 +328,10 @@ public void testMdcValuesAreConvertedToLabelsWithPassingNullValues() {
294328
logging.setFlushSeverity(Severity.ERROR);
295329
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
296330
logging.write(
297-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
331+
capture(capturedArgument),
332+
anyObject(WriteOption.class),
333+
anyObject(WriteOption.class),
334+
anyObject(WriteOption.class));
298335
expectLastCall().once();
299336
replay(logging);
300337
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(100000, 0);
@@ -317,7 +354,10 @@ public void testAddCustomLoggingEventEnhancers() {
317354
logging.setFlushSeverity(Severity.ERROR);
318355
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
319356
logging.write(
320-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
357+
capture(capturedArgument),
358+
anyObject(WriteOption.class),
359+
anyObject(WriteOption.class),
360+
anyObject(WriteOption.class));
321361
expectLastCall().once();
322362
replay(logging);
323363
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(100000, 0);
@@ -338,7 +378,10 @@ public void testAddCustomLoggingEnhancer() {
338378
logging.setFlushSeverity(Severity.ERROR);
339379
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
340380
logging.write(
341-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
381+
capture(capturedArgument),
382+
anyObject(WriteOption.class),
383+
anyObject(WriteOption.class),
384+
anyObject(WriteOption.class));
342385
expectLastCall().once();
343386
replay(logging);
344387
loggingAppender.addEnhancer(CustomLoggingEnhancer.class.getName());
@@ -359,6 +402,7 @@ public void testFlush() {
359402
logging.write(
360403
EasyMock.<Iterable<LogEntry>>anyObject(),
361404
anyObject(WriteOption.class),
405+
anyObject(WriteOption.class),
362406
anyObject(WriteOption.class));
363407
expectLastCall().times(2);
364408
logging.flush();
@@ -395,6 +439,7 @@ public void testAutoPopulationEnabled() {
395439
logging.write(
396440
EasyMock.<Iterable<LogEntry>>anyObject(),
397441
anyObject(WriteOption.class),
442+
anyObject(WriteOption.class),
398443
anyObject(WriteOption.class));
399444
expectLastCall().once();
400445
replay(logging);
@@ -460,7 +505,10 @@ public void testFDiagnosticInfoAdded() {
460505
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
461506
logging.setFlushSeverity(Severity.ERROR);
462507
logging.write(
463-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
508+
capture(capturedArgument),
509+
anyObject(WriteOption.class),
510+
anyObject(WriteOption.class),
511+
anyObject(WriteOption.class));
464512
replay(logging);
465513
LoggingEvent loggingEvent =
466514
createLoggingEvent(Level.ERROR, Timestamp.ofTimeSecondsAndNanos(100000, 0).getSeconds());
@@ -502,7 +550,10 @@ public void testFDiagnosticInfoNotAdded() {
502550
logging.setFlushSeverity(Severity.ERROR);
503551
Capture<Iterable<LogEntry>> capturedArgument = Capture.newInstance();
504552
logging.write(
505-
capture(capturedArgument), anyObject(WriteOption.class), anyObject(WriteOption.class));
553+
capture(capturedArgument),
554+
anyObject(WriteOption.class),
555+
anyObject(WriteOption.class),
556+
anyObject(WriteOption.class));
506557
replay(logging);
507558
LoggingEvent loggingEvent =
508559
createLoggingEvent(Level.WARN, Timestamp.ofTimeSecondsAndNanos(100000, 0).getSeconds());

0 commit comments

Comments
 (0)