We're using spring-boot-starter-parent 2.7 • The java.version property is 17 • We're using starters for: ◦ actuator, web, data-jpa, and security • We're using PostgreSQL
• Dog and Owner JPA classes map to the schema • DogRepository and OwnerRepository are Spring Data repositories ◦ findByNameIgnoringCase is converted to JQL automatically • InfoLogger is an ApplicationRunner to log info at startup
• DogsController ◦ Simple controller used for testing • OwnerController ◦ Delegates to the OwnerService ◦ Deals with NoSuchDogOwnerException ◦ Note: Meta-annotated @RestController and @GetMapping
• SecurityConfiguration ◦ Defines our web security • SecurityProperties and UserProperties ◦ @ConfigurationProperties maps from values in src/main/resources/application.yml
Inspect application.yml ◦ Defines the database connection ◦ Configures JPA ◦ Enables JMX ◦ Configures server errors ◦ Exposes all actuator endpoints ◦ Enables actuators over HTTP ◦ Customizes a metric name ◦ Defines the in-memory user details
http -a user:password "http://localhost:8080/owner/scott/dogs" $ http -a user:password "http://localhost:8080/owner/jonatan/dogs" $ http -a user:password "http://localhost:8080/owner/dave/dogs" NoSuchOwnerException mapped to HTTP 404
the following in a web browser: http://localhost:8080/actuator http://localhost:8080/actuator/env (search for password) http://localhost:8080/actuator/metrics/ http://localhost:8080/actuator/metrics/http.server.in
javax package namespace can't be used by Jakarta • So the Dog and Owner classes now have invalid imports • Replace javax.persistence with jakarta.persistence
no longer extends CrudRepository • There are new convenient List... interfaces • Change DogRepository to extend ListCrudRepository and ListPagingAndSortingRepository • Change OwnerRepository to extend ListCrudRepository
means findAll now returns List not Iterable • Change InfoLogger log calls to no longer use StreamSupport ◦ this.dogRepository.findAll() ◦ this.ownerRepository.findAll()
moved and we need to fix that • Update SecurityProperties and UserProperties ◦ Replace import org.springframework.boot.context.properties.Const ructorBinding ◦ With import org.springframework.boot.context.properties.bind. ConstructorBinding
application and it will report deprecations and replacements $ ./mvnw -pl dog-service clean spring-boot:run … The use of configuration keys that have been renamed was found in the environment: Property source 'Config resource 'class path resource [application.yml]' via location 'optional:classpath:/'': Key: management.metrics.web.server.request.metric-name Line: 25 Replacement: management.observations.http.server.requests.name
spring-boot:run • Check the actuator env endpoint ◦ Notice that all values are hidden with ****** • Try JMX actuator with jconsole ◦ Notice that only health is available
is now aligned with web and needs to be exposed • Add management.endpoints.jmx.exposure.include with a value of "*" • Run the app again and check JMX in jconsole
little and apps are going down there We need to deal with unknown unknowns We can’t know everything Things can be perceived differently by observers Everything is broken for the users but seems ok to you Why do we need Observability?
from production incidents Lower mean time to recovery (MTTR) Require less specialized knowledge Shared method of investigating across system Quantify user experience Don't guess, measure!
150 ms Distributed Tracing DB was slow (lot of data was requested) Error Logging Processing failed (stacktrace?) Metrics The error rate is 0.001/sec 2 errors in the last 30 minutes Distributed Tracing DB call failed (invalid input)
Java) Simple API for logging libraries Logback Natively implements the SLF4J API If you want Log4j2 instead of Logback: - spring-boot-starter-logging + spring-boot-starter-log4j2 Logging with JVM/Spring: SLF4J + Logback
something that we can use to query: ◦ All of our apps (spring.application.org) ◦ Only one app (spring.application.name) ◦ Only one instance (we only have one instance/app) spring: application: name: dog-service org: petclinic
Grafana: http://localhost:3000 • Choose Explore, then Loki from the drop down • Search for application = dog-service • Search for org = petclinic • We will get back to our logs later
Like SLF4J, but for metrics API is independent of the configured metrics backend Supports many backends Comes with spring-boot-actuator Spring projects are instrumented using Micrometer Many third-party libraries use Micrometer
🧐 • Prometheus? http://localhost:9090/targets • Spring Security! 👀 • Let’s disable it, what could go wrong!? 😈 • Everything, please don’t do this in prod! • Except if you want everyone know about it. 😈
We want to see the latency distributions on our dashboards • We want to calculate percentiles (P99?) management: metrics: distribution: percentiles-histogram: # all: true http.server.requests: true
• Let’s check /actuator/metrics /actuator/metrics/{metricName} /actuator/metrics/{metricName}?tag=key:value • Let’s write a Prometheus query (HELP.md) sum by (application) (rate(http_server_requests_seconds_count[5m])) • Let’s check the dashboards: go to Grafana, then Browse ◦ Spring Boot Statistics ◦ Dogs
3.x: Micrometer Tracing (Sleuth w/o Spring dependencies) Provide an abstraction layer on top of tracing libraries - Brave (OpenZipkin), default - OpenTelemetry (CNCF), experimental Instrumentation for Spring Projects, 3rd party libraries, your app Support for various backends
are on Spring Boot 3.1 or above, this is not needed • If you are on 3.0, you need to set logging.pattern.level • We are on 3.2! logging: level: org.springframework.web.servlet.DispatcherServlet: DEBUG
available if you request the OpenMetrics format • Your browser does not do this http :8081/actuator/prometheus / 'Accept: application/openmetrics-text;version=1.0.0' | grep trace_id
(up, down) when the Spring Boot application starts and stops • Inspects started containers and detects known service types ◦ MariaDB ◦ MySQL ◦ Oracle ◦ Postgres ◦ SQL Server ◦ MongoDB ◦ Redis ◦ Elasticsearch ◦ Neo4j ◦ Kafka ◦ RabbitMQ ◦ etc
compose down ; cd .. $ ./mvnw -pl dog-service clean spring-boot:run INFO 63485 --- [dog-service] o.s.b.d.c.l.DockerComposeLifecycleManager : Using Docker Compose file '/home/projects/dn24-boot3-workshop/dog-service/docker-compose.yml' INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container tempo Created INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container postgres Created INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container loki Created INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container prometheus Created INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container grafana Created INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container loki Starting INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container grafana Starting INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container prometheus Starting INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container tempo Starting INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container postgres Starting INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container grafana Started INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container postgres Started INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container prometheus Started INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container tempo Started INFO 63485 --- [dog-service] o.s.boot.docker.compose.core.DockerCli : Container loki Started
are supported automatically ◦ Additional images can be supported with a label in compose file • Docker compose lifecycle can be customized ◦ Start (up, start) and stop (down, stop) commands ◦ Start and Stop, Start only, and none lifecycle options • Docker compose profiles can be activated ◦ Distinct from Spring profiles, but the concepts can be combined • Container readiness checks can be customized https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.docker-compose
Java APIs • Eases the development of integration tests • Modules are provided for many common services that Spring Boot provides auto-configuration for • Containers can be inspected once they are started to get necessary connection information https://java.testcontainers.org/ https://testcontainers.com/modules/
… [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.example.dogservice.domain.RepositoryIntegrationTests … [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.077 s -- in com.example.dogservice.domain.RepositoryIntegrationTests
… [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] [INFO] Running com.example.dogservice.service.DogServiceIntegrationTests … [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.251 s -- in com.example.dogservice.service.DogServiceIntegrationTests
Specifications and APIs for building modular and composable buildpacks that contribute to building OCI images • Implementations provided by Paketo, Google, Heroku, and others • Alternative to Dockerfiles and Jib https://buildpacks.io/
base layers (OS, JRE) • Rebasing of images without re-creating all layers • Automatic Software Bill-of-Materials (SBOM) generation • Broad community support https://www.youtube.com/watch?v=TX_UXuzqVGQ
default ◦ Can be configured to install Adoptium, Dragonwell, Corretto, Zulu, OpenJ9, GraalVM, Oracle, Microsoft OpenJDK instead ◦ Can install a JRE or JDK • java-native ◦ Builds a GraalVM native image when detecting a Spring Boot AOT-enabled application https://paketo.io https://paketo.io/docs/reference/java-reference/ https://paketo.io/docs/howto/java/
<configuration> <image> <builder>paketobuildpacks/builder-jammy-buildpackless-tiny</builder> <buildpacks> <buildpack>paketobuildpacks/java:beta</buildpack> </buildpacks> </image> </configuration> </plugin> Building an OCI Image on a Mac M1/M2
Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections. at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl (ConnectionFactoryImpl.java:342) at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:54) at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:263) at org.postgresql.Driver.makeConnection(Driver.java:443) at org.postgresql.Driver.connect(Driver.java:297)
are useful for fast iteration and inner-loop development • Production images should be built in a CI platform that supports CNB ◦ Tekton ◦ Tanzu Build Service ◦ GitHub Actions ◦ AWS CodeBuild ◦ Google Cloud Build