Skip to content

Instantly share code, notes, and snippets.

@igorferreira
Created September 29, 2020 01:26
Show Gist options
  • Save igorferreira/2bdad7bd2ec3a29bd05252cc87119966 to your computer and use it in GitHub Desktop.
Save igorferreira/2bdad7bd2ec3a29bd05252cc87119966 to your computer and use it in GitHub Desktop.
Configurando Spring-boot com Prometheus - Tudo que vc precisa para testar local
package dev.igorferreira.prometheusspringboot.security;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.json.JsonSanitizer;
import dev.igorferreira.prometheusspringboot.response.StatusResponse;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class ActuatorBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Value("${spring.security.user.realm}")
private String realm;
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String statusResponseJson = mapper.writeValueAsString(
StatusResponse.builder().status(String.valueOf(HttpStatus.UNAUTHORIZED.value()))
.mensagem(authException.getMessage()).build());
String statusResponseJsonSanitized = JsonSanitizer.sanitize(statusResponseJson);
log.warn("\n\n Chamada não autorizada em: {} \n\n Resposta: {} \n", request.getRequestURI(),statusResponseJsonSanitized);
response.setStatus(SC_UNAUTHORIZED);
response.setContentType(APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
response.getOutputStream().write(statusResponseJsonSanitized.getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
}
@Override
public void afterPropertiesSet(){
setRealmName(realm);
super.afterPropertiesSet();
}
}
package dev.igorferreira.prometheusspringboot.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${spring.security.user.realm}")
private String realm;
@Value("${management.endpoints.env.roles}")
private String role;
@Autowired
private ActuatorBasicAuthenticationEntryPoint authenticationEntryPoint;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/restws/","/restws/**").permitAll()
.antMatchers("/actuator/beans",
"/actuator/caches/**",
"/actuator/conditions",
"/actuator/configprops",
"/actuator/env/**",
"/actuator/loggers/**",
"/actuator/heapdump/**",
"/actuator/threaddump/**",
"/actuator/scheduledtasks",
"/actuator/mappins",
"/actuator/shutdown")
.hasRole(role)
.antMatchers("/webjars/swagger-ui/**",
"/swagger-ui")
.hasRole(role)
.and()
.formLogin()
.and()
.httpBasic()
.realmName(realm)
.authenticationEntryPoint(authenticationEntryPoint);
http.csrf().disable();
}
}
spring:
application:
name: '@project.name@'
profiles:
active: '@spring.profiles.active@'
mandatory-file-encoding: UTF-8
jackson.serialization.FAIL_ON_EMPTY_BEANS: false
security:
user:
name: admin
password: "admin@123"
roles: ACTUATOR,USER
realm: "ACTUATOR_REALM"
management:
server.port: ${server.port}
info.git.mode: full
endpoints:
env.roles: ACTUATOR
enabled-by-default: true
web:
cors:
allowed-origins: "*"
allowed-methods: GET,POST
exposure:
include: "*"
metrics:
export:
prometheus:
enabled: true
pushgateway:
enabled: true
version: '3.8'
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3000:3000"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>dev.igorferreira.prometheusspringboot</groupId>
<artifactId>prometheus-spring-boot</artifactId>
<version>1.0.0</version>
<name>prometheus-spring-boot</name>
<description>Exemplo para usar springboot com prometheus</description>
<properties>
<project.version>1.0.0</project.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<file.encoding>UTF-8</file.encoding>
<java.version>1.8</java.version>
<compileSource>1.8</compileSource>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<git-commit-id-plugin.skip>false</git-commit-id-plugin.skip>
<logbook.version>2.2.0</logbook.version>
<spring-boot-maven-plugin.excludeDevtools>false</spring-boot-maven-plugin.excludeDevtools>
<javax.activation.version>1.2.0</javax.activation.version>
<jaxb.api.version>2.3.0</jaxb.api.version>
<!-- test -->
<maven.test.skip>true</maven.test.skip>
<junit.jupiter.version>5.6.2</junit.jupiter.version>
<junit.platform.version>1.6.2</junit.platform.version>
<hamcrest-all.version>1.3</hamcrest-all.version>
<mockito.version>2.24.0</mockito.version>
</properties>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>${javax.activation.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.api.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>${jaxb.api.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.api.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring-boot initializer - https://start.spring.io/ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<!-- fix conflict with 'org.json:json:jar:20160212' in 'org.apache.camel.springboot:camel-jsonpath-starter' -->
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
<!-- remove junit4 compatibility -->
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- spring-boot initializer no https://start.spring.io/ -->
<!-- add javaee libraries for jdk11 -->
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
<!-- prometheus -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>com.mikesamuel</groupId>
<artifactId>json-sanitizer</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>${hamcrest-all.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.26.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<defaultGoal>clean package</defaultGoal>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</testResource>
</testResources>
<pluginManagement>
<plugins>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<profiles>
<profile>local</profile>
</profiles>
<arguments>
<argument>-Dserver.port=8081</argument>
<argument>-Dsulamerica.logapproot.level=INFO</argument>
<argument>-Dsulamerica.logapp.rootdir=/opt/log-app</argument>
<argument>-Djava.security.egd=file:/dev/./urandom</argument>
<argument>-Djava.net.preferIPv4Stack=true</argument>
<argument>-Duser.timezone=America/Sao_Paulo</argument>
<argument>-Duser.language=pt</argument>
<argument>-Duser.country=BR</argument>
<argument>-Dfile.encoding=UTF-8</argument>
</arguments>
<excludeDevtools>${spring-boot-maven-plugin.excludeDevtools}</excludeDevtools>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<executions>
<execution>
<id>validate-the-git-infos</id>
<goals>
<goal>validateRevision</goal>
</goals>
</execution>
</executions>
<configuration>
<skip>${git-commit-id-plugin.skip}</skip>
<verbose>false</verbose>
<dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>src/main/resources/git.properties</generateGitPropertiesFilename>
<format>properties</format>
<dateFormat>dd-MM-yyyy '@' HH:mm:ss z</dateFormat>
<gitDescribe>
<skip>false</skip>
<always>false</always>
<dirty>-dirty</dirty>
<forceLongFormat>true</forceLongFormat>
</gitDescribe>
</configuration>
</plugin>
</plugins>
</build>
</project>
ActuatorBasicAuthenticationEntryPoint
========
@Component
public class ActuatorBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Value("${spring.security.user.realm}")
private String realm;
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException) throws IOException {
ObjectMapper mapper = new ObjectMapper();
String statusResponseJson = mapper.writeValueAsString(
StatusResponse.builder().status(String.valueOf(HttpStatus.UNAUTHORIZED.value()))
.mensagem(authException.getMessage()).build());
String statusResponseJsonSanitized = JsonSanitizer.sanitize(statusResponseJson);
response.setStatus(SC_UNAUTHORIZED);
response.setContentType(APPLICATION_JSON_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
response.getOutputStream().write(statusResponseJsonSanitized.getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
}
@Override
public void afterPropertiesSet(){
setRealmName(realm);
super.afterPropertiesSet();
}
}
ActuatorSecurityConfiguration
========
@Configuration
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${spring.security.user.realm}")
private String realm;
@Value("${management.endpoints.env.roles}")
private String role;
@Autowired
private ActuatorBasicAuthenticationEntryPoint authenticationEntryPoint;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/restws/","/restws/**").permitAll()
.antMatchers("/actuator/beans",
"/actuator/caches/**",
"/actuator/conditions",
"/actuator/configprops",
"/actuator/env/**",
"/actuator/loggers/**",
"/actuator/heapdump/**",
"/actuator/threaddump/**",
"/actuator/scheduledtasks",
"/actuator/mappins",
"/actuator/shutdown")
.hasRole(role)
.antMatchers("/webjars/swagger-ui/**",
"/swagger-ui")
.hasRole(role)
.and()
.formLogin()
.and()
.httpBasic()
.realmName(realm)
.authenticationEntryPoint(authenticationEntryPoint);
http.csrf().disable();
}
application.yml
========
spring:
application:
name: '@project.name@'
profiles:
active: '@spring.profiles.active@'
mandatory-file-encoding: UTF-8
jackson.serialization.FAIL_ON_EMPTY_BEANS: false
security:
user:
name: admin
password: "admin@123"
roles: ACTUATOR,USER
realm: "ACTUATOR_REALM"
management:
server.port: ${server.port}
info.git.mode: full
endpoints:
env.roles: ACTUATOR
enabled-by-default: true
web:
cors:
allowed-origins: "*"
allowed-methods: GET,POST
exposure:
include: "*"
metrics:
export:
prometheus:
enabled: true
pushgateway:
enabled: true
pom.xml
========
<!-- prometheus -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
docker-compose.yml
========
version: '3.8'
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3000:3000"
prometheus.yml
========
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
labels:
grupo: 'Prometheus'
- job_name: 'picpayclone'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
static_configs:
- targets: ['localhost:7001']
labels:
app: 'picpayclone'
api: 'api-transacao'
data: '2020-09-28'
dashboards
========
https://grafana.com/grafana/dashboards
https://grafana.com/grafana/dashboards/4701
# dashboard jvm micrometer
# https://grafana.com/grafana/dashboards/4701
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
labels:
grupo: 'Prometheus'
- job_name: 'picpayclone'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
static_configs:
- targets: ['localhost:8080']
labels:
app: 'prometheusspringboot'
data: '2020-09-28'
package dev.igorferreira.prometheusspringboot.response;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class StatusResponse implements Serializable {
private static final long serialVersionUID = 2642223915664809487L;
@JsonProperty("status")
private String status;
@JsonProperty("mensagem")
private String mensagem;
@Override
public String toString() {
try {
return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
} catch (JsonProcessingException e) {
return e.getLocalizedMessage();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment