Skip to content

Commit 25c9e13

Browse files
committed
Adds filebeat integration for centralized logging
Implements filebeat for centralized log management in production. This change introduces Filebeat to collect and ship logs to Elasticsearch, enabling centralized logging and improved monitoring capabilities. It includes configurations for Docker autodiscovery, JSON log decoding, and integration with the Elastic Stack. It also adds a request logging filter to log HTTP requests, and it configures logback to output JSON format suitable for filebeat. Adds .env* and logs/ to .gitignore to prevent committing those files.
1 parent 500f067 commit 25c9e13

File tree

13 files changed

+225
-6
lines changed

13 files changed

+225
-6
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: ["*"]
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/scheduler/CoordenadasScheduler.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
@Component
1818
public class CoordenadasScheduler {
1919

20+
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CoordenadasScheduler.class);
2021
private final APIService apiService;
2122
private final OnibusService onibusService;
2223

@@ -29,8 +30,10 @@ public CoordenadasScheduler(APIService apiService, OnibusService onibusService)
2930
public void fetchCoordenadasOnibus() {
3031
try {
3132
MDC.put("transaction_id", UUID.randomUUID().toString());
33+
logger.info("Job de Coordenadas iniciado.");
3234
List<CoordenadaDTO> coordenadas = apiService.getOnibusCoordenadaBH();
3335
onibusService.salvaCoordenadas(coordenadas);
36+
logger.info("Job de Coordenadas finalizado.");
3437
} finally {
3538
MDC.clear();
3639
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
@Component
1515
public class DicionarioScheduler {
1616

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

1920
public DicionarioScheduler(DicionarioService dicionarioService) {
@@ -25,7 +26,9 @@ public DicionarioScheduler(DicionarioService dicionarioService) {
2526
public void salvaDicionarioBanco() {
2627
try {
2728
MDC.put("transaction_id", UUID.randomUUID().toString());
29+
logger.info("Job de Dicionário iniciado.");
2830
dicionarioService.salvarDicionarioBanco();
31+
logger.info("Job de Dicionário finalizado.");
2932
} finally {
3033
MDC.clear();
3134
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
@Component
1515
public class LinhaScheduler {
1616

17+
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(LinhaScheduler.class);
1718
private final LinhasService linhasService;
1819

1920
public LinhaScheduler(LinhasService linhasService) {
@@ -25,7 +26,9 @@ public LinhaScheduler(LinhasService linhasService) {
2526
public void fetchCoordenadasOnibus() {
2627
try {
2728
MDC.put("transaction_id", UUID.randomUUID().toString());
29+
logger.info("Job agendado iniciado: Atualização de Coordenadas/Linhas.");
2830
linhasService.salvaLinhasNormais();
31+
logger.info("Job agendado finalizado: Atualização de Coordenadas/Linhas.");
2932
} finally {
3033
MDC.clear();
3134
}

src/main/java/com/dmware/api_onibusbh/services/DicionarioService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void salvarDicionarioBanco() {
7878
dicionarioRepository
7979
.saveAll(modelMapper.map(dadosParaSalvar, new TypeToken<List<DicionarioEntity>>() {
8080
}.getType()));
81-
logger.info("Sincronização de dicionário concluída", kv("total_processado", dadosParaSalvar.size()));
81+
logger.info("Sincronização de dicionário concluída. Total de itens processados: {}", dadosParaSalvar.size(), kv("total_processado", dadosParaSalvar.size()));
8282
} else {
8383
logger.info("Nenhuma alteração necessária no dicionário");
8484
}

0 commit comments

Comments
 (0)