Skip to content

Commit 6b23573

Browse files
committed
Merge branch 'testing'
2 parents 07f9c35 + 25c9e13 commit 6b23573

File tree

16 files changed

+341
-50
lines changed

16 files changed

+341
-50
lines changed

.github/workflows/deploy.yml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,26 @@ jobs:
2828
push: true
2929
tags: ${{ secrets.DOCKER_USERNAME }}/api-onibusbh:latest
3030

31+
- name: Copy config to EC2
32+
uses: appleboy/scp-action@master
33+
with:
34+
host: ${{ secrets.EC2_HOST }}
35+
username: ${{ secrets.EC2_USERNAME }}
36+
key: ${{ secrets.EC2_SSH_KEY }}
37+
source: "filebeat.prod.yml"
38+
target: "/home/${{ secrets.EC2_USERNAME }}/api-onibusbh/"
39+
3140
- name: Deploy to EC2
3241
uses: appleboy/ssh-action@master
3342
with:
3443
host: ${{ secrets.EC2_HOST }}
3544
username: ${{ secrets.EC2_USERNAME }}
3645
key: ${{ secrets.EC2_SSH_KEY }}
3746
script: |
38-
docker stop api-onibusbh || true
39-
docker rm api-onibusbh || true
47+
WORKDIR="/home/${{ secrets.EC2_USERNAME }}/api-onibusbh"
48+
49+
docker stop api-onibusbh filebeat-prod || true
50+
docker rm api-onibusbh filebeat-prod || true
4051
4152
docker pull ${{ secrets.DOCKER_USERNAME }}/api-onibusbh:latest
4253
@@ -49,4 +60,17 @@ jobs:
4960
-e MONGO_DATABASE=${{ secrets.MONGO_DATABASE }} \
5061
-e MONGO_USERNAME=${{ secrets.MONGO_USERNAME }} \
5162
-e MONGO_PASSWORD=${{ secrets.MONGO_PASSWORD }} \
63+
-e ELASTIC_HOST=${{ secrets.ELASTIC_HOST }} \
64+
--restart unless-stopped \
5265
${{ secrets.DOCKER_USERNAME }}/api-onibusbh:latest
66+
67+
docker run -d \
68+
--name filebeat-prod \
69+
--user root \
70+
--restart unless-stopped \
71+
-e ELASTIC_HOST=${{ secrets.ELASTIC_HOST }} \
72+
-v /var/lib/docker/containers:/var/lib/docker/containers:ro \
73+
-v /var/run/docker.sock:/var/run/docker.sock:ro \
74+
-v $WORKDIR/filebeat.prod.yml:/usr/share/filebeat/filebeat.yml:ro \
75+
docker.elastic.co/beats/filebeat:8.15.0 \
76+
--strict.perms=false

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,11 @@ build/
3131

3232
### VS Code ###
3333
.vscode/
34+
35+
### Environment ###
36+
.env
37+
.env.*
38+
39+
### Logs ###
40+
logs/
41+
*.log

compose.yaml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,20 @@ services:
66
- MONGO_INITDB_ROOT_PASSWORD=E0K64Y7sAqNYqOAx
77
- MONGO_INITDB_ROOT_USERNAME=admin
88
ports:
9-
- "27017:27017"
9+
- "27017:27017"
10+
11+
filebeat:
12+
image: docker.elastic.co/beats/filebeat:8.11.1
13+
user: root
14+
environment:
15+
- ELASTIC_HOST=${ELASTIC_HOST}
16+
dns:
17+
- 8.8.8.8
18+
- 8.8.4.4
19+
volumes:
20+
- /var/lib/docker/containers:/var/lib/docker/containers:ro
21+
- /var/run/docker.sock:/var/run/docker.sock:ro
22+
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
23+
- ./logs:/host_logs:ro
24+
command: ["--strict.perms=false"]
25+
restart: unless-stopped

filebeat.prod.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
filebeat.autodiscover:
2+
providers:
3+
- type: docker
4+
hints.enabled: true
5+
templates:
6+
- condition:
7+
contains:
8+
docker.container.name: springboot-app_prod
9+
config:
10+
- type: container
11+
paths:
12+
- /var/lib/docker/containers/${data.docker.container.id}/*.log
13+
processors:
14+
- decode_json_fields:
15+
fields: ["message"]
16+
target: ""
17+
overwrite_keys: true
18+
add_error_key: true
19+
20+
processors:
21+
- add_docker_metadata: ~
22+
- add_cloud_metadata: ~
23+
- add_tags:
24+
tags: ["production", "api-onibusbh"]
25+
26+
output.elasticsearch:
27+
hosts: ['${ELASTIC_HOST}']
28+
protocol: "https"
29+
# ssl.verification_mode: none

filebeat.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
filebeat.inputs:
2+
- type: log
3+
enabled: true
4+
paths:
5+
- /host_logs/*.json
6+
json.keys_under_root: true
7+
json.overwrite_keys: true
8+
processors:
9+
- add_tags:
10+
tags: ["local_dev_ide"]
11+
12+
- type: container
13+
paths:
14+
- '/var/lib/docker/containers/*/*.log'
15+
processors:
16+
- add_docker_metadata:
17+
host: "unix:///var/run/docker.sock"
18+
19+
- drop_event:
20+
when:
21+
not:
22+
contains:
23+
container.name: "springboot-app_prod"
24+
25+
- decode_json_fields:
26+
fields: ["message"]
27+
target: ""
28+
overwrite_keys: true
29+
process_array: false
30+
max_depth: 1
31+
32+
output.elasticsearch:
33+
hosts: ["${ELASTIC_HOST:localhost:9200}"]
34+
ssl.verification_mode: none
35+
36+
index: "api-onibusbh-prod-%{+yyyy.MM.dd}"
37+
38+
setup.template.name: "api-onibusbh"
39+
setup.template.pattern: "api-onibusbh-*"
40+
setup.ilm.enabled: false
41+
42+
logging.level: debug
43+
logging.to_stderr: true
44+
logging.selectors: ["*"]

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@
8484
<artifactId>jackson-datatype-jsr310</artifactId>
8585
</dependency>
8686

87+
<dependency>
88+
<groupId>net.logstash.logback</groupId>
89+
<artifactId>logstash-logback-encoder</artifactId>
90+
<version>9.0</version>
91+
</dependency>
8792
</dependencies>
8893

8994
<build>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.dmware.api_onibusbh.config;
2+
3+
import jakarta.servlet.FilterChain;
4+
import jakarta.servlet.ServletException;
5+
import jakarta.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import org.slf4j.MDC;
10+
import org.springframework.stereotype.Component;
11+
import org.springframework.web.filter.OncePerRequestFilter;
12+
13+
import java.io.IOException;
14+
import java.util.UUID;
15+
16+
import static net.logstash.logback.argument.StructuredArguments.kv;
17+
18+
@Component
19+
public class RequestLoggingFilter extends OncePerRequestFilter {
20+
21+
private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);
22+
private static final String TRANSACTION_ID_KEY = "transaction_id";
23+
24+
@Override
25+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
26+
throws ServletException, IOException {
27+
28+
long startTime = System.currentTimeMillis();
29+
30+
String transactionId = request.getHeader("X-Transaction-ID");
31+
if (transactionId == null || transactionId.isEmpty()) {
32+
transactionId = UUID.randomUUID().toString();
33+
}
34+
35+
MDC.put(TRANSACTION_ID_KEY, transactionId);
36+
37+
try {
38+
logger.info("Requisição recebida: {} {}", request.getMethod(), request.getRequestURI(),
39+
kv("method", request.getMethod()),
40+
kv("uri", request.getRequestURI()),
41+
kv("client_ip", request.getRemoteAddr()),
42+
kv("user_agent", request.getHeader("User-Agent"))
43+
);
44+
45+
filterChain.doFilter(request, response);
46+
47+
long duration = System.currentTimeMillis() - startTime;
48+
49+
logger.info("Requisição finalizada: {} {} - Status: {} - Tempo: {}ms",
50+
request.getMethod(),
51+
request.getRequestURI(),
52+
response.getStatus(),
53+
duration,
54+
kv("status_code", response.getStatus()),
55+
kv("duration_ms", duration)
56+
);
57+
58+
} finally {
59+
MDC.remove(TRANSACTION_ID_KEY);
60+
}
61+
}
62+
}

src/main/java/com/dmware/api_onibusbh/infra/CustomExceptionHandler.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.dmware.api_onibusbh.infra;
22

33
import com.dmware.api_onibusbh.exceptions.*;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
46
import org.springframework.http.HttpStatus;
57
import org.springframework.http.ResponseEntity;
68
import org.springframework.web.bind.annotation.ControllerAdvice;
@@ -11,54 +13,66 @@
1113

1214
import java.io.IOException;
1315

16+
import static net.logstash.logback.argument.StructuredArguments.kv;
17+
1418
@ControllerAdvice
1519
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
1620

21+
private static final Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);
22+
1723
@ExceptionHandler(LinhasNotFoundException.class)
1824
public ResponseEntity<ErrorResponse> linhasNotFoundException(LinhasNotFoundException ex) {
25+
logger.warn("Recurso não encontrado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.NOT_FOUND));
1926
return ErrorResponse.of("Não foi encontrada nenhuma linha, por favor tente novamente", HttpStatus.NOT_FOUND);
2027
}
2128

2229
@ExceptionHandler(CoordenadasNotFoundException.class)
2330
public ResponseEntity<ErrorResponse> coordenadasNotFoundException(CoordenadasNotFoundException ex) {
31+
logger.warn("Recurso não encontrado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.NOT_FOUND));
2432
return ErrorResponse.of("Não foi encontrada nenhuma coordenada, por favor tente novamente",
2533
HttpStatus.NOT_FOUND);
2634
}
2735

2836
@ExceptionHandler(DicionarioNotFoundException.class)
2937
public ResponseEntity<ErrorResponse> dicionarioNotFoundException(DicionarioNotFoundException ex) {
38+
logger.warn("Recurso não encontrado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.NOT_FOUND));
3039
return ErrorResponse.of("Não foi encontrado o dicionário para os dados, por favor tente novamente",
3140
HttpStatus.NOT_FOUND);
3241
}
3342

3443
@ExceptionHandler(LinhaNotFoundException.class)
3544
public ResponseEntity<ErrorResponse> linhaNotFoundException(LinhaNotFoundException ex) {
45+
logger.warn("Recurso não encontrado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.NOT_FOUND));
3646
return ErrorResponse.of("Não foi encontrada nenhuma linha, por favor tente novamente", HttpStatus.NOT_FOUND);
3747
}
3848

3949
@ExceptionHandler(ValidJsonException.class)
4050
public ResponseEntity<ErrorResponse> validJsonException(ValidJsonException ex) {
51+
logger.warn("Erro de validação JSON", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.BAD_REQUEST), kv("mensagem_erro", ex.getMessage()));
4152
return ErrorResponse.of(ex.getMessage(), HttpStatus.BAD_REQUEST);
4253
}
4354

4455
@ExceptionHandler(RuntimeException.class)
4556
public ResponseEntity<ErrorResponse> runtimeException(RuntimeException ex) {
46-
logger.error(ex.getMessage(), ex);
57+
logger.error("Erro interno não tratado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.INTERNAL_SERVER_ERROR), ex);
4758
return ErrorResponse.of("Ocorreu um erro interno, por favor tente novamente", HttpStatus.INTERNAL_SERVER_ERROR);
4859
}
4960

5061
@ExceptionHandler(IOException.class)
5162
public ResponseEntity<ErrorResponse> ioException(IOException ex) {
63+
logger.error("Erro interno não tratado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.INTERNAL_SERVER_ERROR), ex);
5264
return ErrorResponse.of("Ocorreu um erro interno, por favor tente novamente", HttpStatus.INTERNAL_SERVER_ERROR);
5365
}
5466

5567
@ExceptionHandler(NoResourceFoundException.class)
5668
public ResponseEntity<ErrorResponse> noResourceFoundException(NoResourceFoundException ex) {
69+
logger.warn("Recurso não encontrado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.NOT_FOUND));
5770
return ErrorResponse.of("Verifique a rota digitada ou os dados enviados", HttpStatus.NOT_FOUND);
5871
}
5972

6073
@ExceptionHandler(NoHandlerFoundException.class)
6174
public ResponseEntity<ErrorResponse> noHandlerFoundException(NoHandlerFoundException ex) {
75+
logger.warn("Recurso não encontrado", kv("exception", ex.getClass().getSimpleName()), kv("status", HttpStatus.NOT_FOUND));
6276
return ErrorResponse.of("Verifique a rota digitada ou os dados enviados", HttpStatus.NOT_FOUND);
6377
}
6478
}

src/main/java/com/dmware/api_onibusbh/scheduler/CoordenadasScheduler.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import java.io.IOException;
44
import java.util.List;
5+
import java.util.UUID;
56
import java.util.concurrent.TimeUnit;
67

78
import com.dmware.api_onibusbh.dto.CoordenadaDTO;
89
import com.dmware.api_onibusbh.services.APIService;
10+
import org.slf4j.MDC;
911
import org.springframework.scheduling.annotation.Async;
1012
import org.springframework.scheduling.annotation.Scheduled;
1113
import org.springframework.stereotype.Component;
@@ -15,6 +17,7 @@
1517
@Component
1618
public class CoordenadasScheduler {
1719

20+
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CoordenadasScheduler.class);
1821
private final APIService apiService;
1922
private final OnibusService onibusService;
2023

@@ -25,8 +28,15 @@ public CoordenadasScheduler(APIService apiService, OnibusService onibusService)
2528

2629
@Scheduled(fixedDelay = 20, timeUnit = TimeUnit.SECONDS)
2730
public void fetchCoordenadasOnibus() {
28-
List<CoordenadaDTO> coordenadas = apiService.getOnibusCoordenadaBH();
29-
onibusService.salvaCoordenadas(coordenadas);
31+
try {
32+
MDC.put("transaction_id", UUID.randomUUID().toString());
33+
logger.info("Job de Coordenadas iniciado.");
34+
List<CoordenadaDTO> coordenadas = apiService.getOnibusCoordenadaBH();
35+
onibusService.salvaCoordenadas(coordenadas);
36+
logger.info("Job de Coordenadas finalizado.");
37+
} finally {
38+
MDC.clear();
39+
}
3040
}
3141

3242
}

src/main/java/com/dmware/api_onibusbh/scheduler/DicionarioScheduler.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.dmware.api_onibusbh.scheduler;
22

3+
import java.util.UUID;
34
import java.util.concurrent.TimeUnit;
45

6+
import org.slf4j.MDC;
57
import org.springframework.beans.factory.annotation.Autowired;
68
import org.springframework.scheduling.annotation.Async;
79
import org.springframework.scheduling.annotation.Scheduled;
@@ -12,6 +14,7 @@
1214
@Component
1315
public class DicionarioScheduler {
1416

17+
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DicionarioScheduler.class);
1518
private final DicionarioService dicionarioService;
1619

1720
public DicionarioScheduler(DicionarioService dicionarioService) {
@@ -21,6 +24,13 @@ public DicionarioScheduler(DicionarioService dicionarioService) {
2124
@Async
2225
@Scheduled(fixedDelay = 12, timeUnit = TimeUnit.HOURS)
2326
public void salvaDicionarioBanco() {
24-
dicionarioService.salvarDicionarioBanco();
27+
try {
28+
MDC.put("transaction_id", UUID.randomUUID().toString());
29+
logger.info("Job de Dicionário iniciado.");
30+
dicionarioService.salvarDicionarioBanco();
31+
logger.info("Job de Dicionário finalizado.");
32+
} finally {
33+
MDC.clear();
34+
}
2535
}
2636
}

0 commit comments

Comments
 (0)