From 6db6a9e9fcdee87123751b3466a15cc690f6a494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Skj=C3=B8lberg?= Date: Mon, 20 Jan 2025 14:02:46 +0100 Subject: [PATCH] Adjust examples / docs --- README.md | 1 + .../web/rest/AsyncDocumentEndpoint.java | 65 +++++++++++++++++ ...emandWebLoggingHttpNotFound1AsyncTest.java | 72 +++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 examples/gcp-web-example/src/main/java/org/entur/example/web/rest/AsyncDocumentEndpoint.java create mode 100644 examples/gcp-web-example/src/test/java/org/entur/example/web/OndemandWebLoggingHttpNotFound1AsyncTest.java diff --git a/README.md b/README.md index c26062b2..52d0231d 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Features: * Selective 'on-demand' logging for unexpected web server behaviour * capture full logs for problematic requests (i.e. not only WARN or ERROR, but also all sibling INFO log statements) * reduce cost of logging considerably + * only supported for sync calls for now * Unit testing * Always assert against machine-readable JSON 'under the hood', regardless what is printed to console during local development * Supported frameworks diff --git a/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/AsyncDocumentEndpoint.java b/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/AsyncDocumentEndpoint.java new file mode 100644 index 00000000..9e6ddf4f --- /dev/null +++ b/examples/gcp-web-example/src/main/java/org/entur/example/web/rest/AsyncDocumentEndpoint.java @@ -0,0 +1,65 @@ +package org.entur.example.web.rest; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.io.CharArrayWriter; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +@RestController +@RequestMapping("/api/async-document") +public class AsyncDocumentEndpoint { + + private final static Logger logger = LoggerFactory.getLogger(AsyncDocumentEndpoint.class); + + @PostMapping("/some/method") + public CompletableFuture someMessage(@RequestBody MyEntity entity) { + logger.trace("Hello entity with secret / trace"); + logger.debug("Hello entity with secret / debug"); + logger.info("Hello entity with secret / info"); + logger.warn("Hello entity with secret / warn"); + logger.error("Hello entity with secret / error"); + + entity.setName("Entur response"); + return CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return entity; + }); + } + + @PostMapping("/some/error") + public CompletableFuture errorMethod(@RequestBody MyEntity entity) throws InterruptedException { + System.out.flush(); + System.out.println("System out before endpoint logging on thread " + Thread.currentThread().getName()); + + logger.trace("This message should be ignored / trace"); + logger.debug("This message should be ignored / debug"); + logger.info("This message should be delayed / info"); + logger.warn("This message should be logged / warn"); + + Thread.sleep(1000); + System.out.println("System out after endpoint logging + 1000ms"); + + return CompletableFuture.supplyAsync(() -> { + System.out.println("Complete future on thread " + Thread.currentThread().getName()); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new ResponseEntity(HttpStatus.NOT_FOUND); + }); + } + + +} \ No newline at end of file diff --git a/examples/gcp-web-example/src/test/java/org/entur/example/web/OndemandWebLoggingHttpNotFound1AsyncTest.java b/examples/gcp-web-example/src/test/java/org/entur/example/web/OndemandWebLoggingHttpNotFound1AsyncTest.java new file mode 100644 index 00000000..aabade8c --- /dev/null +++ b/examples/gcp-web-example/src/test/java/org/entur/example/web/OndemandWebLoggingHttpNotFound1AsyncTest.java @@ -0,0 +1,72 @@ +package org.entur.example.web; + +import no.entur.logging.cloud.logback.logstash.test.CompositeConsoleOutputControl; +import no.entur.logging.cloud.logback.logstash.test.CompositeConsoleOutputControlClosable; +import org.entur.example.web.rest.MyEntity; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * + * Note: Async does not currently work with on-demand logging. + * + */ + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@TestPropertySource(properties = {"entur.logging.http.ondemand.enabled=true", "entur.logging.http.ondemand.failure.http.statusCode.equalOrHigherThan=400"}) +public class OndemandWebLoggingHttpNotFound1AsyncTest { + + @LocalServerPort + private int randomServerPort; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + @Disabled + public void useHumanReadablePlainEncoderExpectFullLogging() { + MyEntity entity = new MyEntity(); + entity.setName("Entur"); + entity.setSecret("mySecret"); + + ResponseEntity response = restTemplate.postForEntity("/api/async-document/some/error", entity, MyEntity.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + @Disabled + public void useHumanReadableJsonEncoderExpectFullLogging() { + try (CompositeConsoleOutputControlClosable c = CompositeConsoleOutputControl.useHumanReadableJsonEncoder()) { + MyEntity entity = new MyEntity(); + entity.setName("Entur"); + entity.setSecret("mySecret"); + + ResponseEntity response = restTemplate.postForEntity("/api/async-document/some/error", entity, MyEntity.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + } + + @Test + @Disabled + public void useMachineReadableJsonEncoderExpectFullLogging() { + try (CompositeConsoleOutputControlClosable c = CompositeConsoleOutputControl.useMachineReadableJsonEncoder()) { + MyEntity entity = new MyEntity(); + entity.setName("Entur"); + entity.setSecret("mySecret"); + + ResponseEntity response = restTemplate.postForEntity("/api/async-document/some/error", entity, MyEntity.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + } + +} \ No newline at end of file