Skip to content

Commit c1ab45d

Browse files
authored
Merge pull request #8 from Delphington/feat-docker-hub
Feat docker hub
2 parents 79405fd + 8e549c4 commit c1ab45d

18 files changed

Lines changed: 640 additions & 178 deletions

File tree

bot/bot.Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM eclipse-temurin:23-jdk-alpine
2+
WORKDIR /app
3+
COPY target/bot-1.0.jar /app/bot-1.0.jar
4+
EXPOSE 8080
5+
CMD ["java", "-jar", "bot-1.0.jar"]

bot/src/main/java/backend/academy/bot/api/controller/UpdateController.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import backend.academy.bot.api.dto.request.LinkUpdate;
44
import backend.academy.bot.notification.NotificationService;
5+
import io.micrometer.core.annotation.Timed;
56
import io.swagger.v3.oas.annotations.Operation;
67
import io.swagger.v3.oas.annotations.responses.ApiResponse;
78
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@@ -31,6 +32,8 @@ public void update(@RequestBody @Valid LinkUpdate linkUpdate) {
3132
}
3233

3334
@PostMapping("/public")
35+
@ResponseStatus(HttpStatus.OK)
36+
@Timed(value = "update.timer", histogram = true) // Явное включение гистограммы
3437
public void update() {
3538
log.info("Пришло обновление по ссылке");
3639
}

bot/src/main/java/backend/academy/bot/command/Command.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import com.pengrad.telegrambot.model.Update;
44
import com.pengrad.telegrambot.request.SendMessage;
5+
import io.micrometer.core.annotation.Timed;
56

67
public interface Command {
78

89
String command();
910

1011
String description();
1112

13+
@Timed("helpCommandMetric")
1214
SendMessage handle(Update update);
1315

1416
default boolean matchesCommand(Update update) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package backend.academy.bot.config;
2+
3+
import io.micrometer.core.instrument.Counter;
4+
import io.micrometer.core.instrument.binder.MeterBinder;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
@Configuration
9+
public class MetricsConfig {
10+
11+
@Bean
12+
public MeterBinder meterBinder() {
13+
return registry -> {
14+
Counter.builder("msg_count")
15+
.description("Количество сообщений от пользователей")
16+
.register(registry);
17+
};
18+
}
19+
}

bot/src/main/java/backend/academy/bot/processor/UserMessageProcessor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.pengrad.telegrambot.request.SendMessage;
1111
import com.pengrad.telegrambot.request.SetMyCommands;
1212
import com.pengrad.telegrambot.response.BaseResponse;
13+
import io.micrometer.core.instrument.MeterRegistry;
1314
import java.util.List;
1415
import lombok.Getter;
1516
import lombok.RequiredArgsConstructor;
@@ -25,6 +26,7 @@ public class UserMessageProcessor {
2526
private final TelegramBot telegramBot;
2627
private final List<Command> commandList;
2728
private final UserStateManager userStateManager;
29+
private final MeterRegistry meterRegistry;
2830

2931
public void registerCommands() {
3032
List<BotCommand> commands = commandList.stream()
@@ -42,6 +44,7 @@ public void registerCommands() {
4244
}
4345

4446
public SendMessage process(Update update) {
47+
meterRegistry.counter("msg_count").increment();
4548
Long id = update.message().chat().id();
4649
userStateManager.createUserIfNotExist(id);
4750

bot/src/main/resources/Metrics.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# RED
2+
3+
Rate
4+
```
5+
sum by(uri, method) (
6+
rate(http_server_requests_seconds_count{job="Bot"}[1m])
7+
)
8+
```
9+
Errors
10+
```
11+
sum by(uri, status) (
12+
rate(http_server_requests_seconds_count{job="Bot", status=~"4..|5.."}[1m])
13+
)
14+
```
15+
Duration
16+
```
17+
sum by(uri) (
18+
rate(http_server_requests_seconds_sum{job="Bot"}[1m])
19+
)
20+
```
21+
22+
# Custom

bot/src/main/resources/application.yaml

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
app:
22
telegram-token: ${TELEGRAM_TOKEN} # env variable
33
link:
4-
scrapper-uri: "http://localhost:8081"
4+
scrapper-uri: "http://scrapper:8081"
55
webclient:
66
timeouts:
77
connect-timeout: 10s # 10 секунд на установку соединения
@@ -30,11 +30,11 @@ spring:
3030
type: redis
3131
data:
3232
redis:
33-
host: localhost
33+
host: redis
3434
port: 6379
3535

3636
kafka:
37-
bootstrap-servers: "localhost:29092"
37+
bootstrap-servers: broker:9092
3838
consumer:
3939
auto-offset-reset: earliest
4040
group-id: "consumer-group"
@@ -131,13 +131,38 @@ bucket4j:
131131
refill-amount: 50 # Количество токенов для пополнения
132132
refill-seconds: 60 # Интервал пополнения в секундах (например, 60 = 1 минута)
133133

134-
135-
136-
137-
#logging:
138-
# structured:
139-
# format:
140-
# file: ecs
141-
# console: ecs
142-
# level:
143-
# root: INFO
134+
management:
135+
server:
136+
port: 8090 # Отдельный порт для метрик
137+
endpoints:
138+
web:
139+
base-path: /
140+
path-mapping:
141+
prometheus: metrics
142+
exposure:
143+
include: "*"
144+
145+
distribution:
146+
percentiles-histogram:
147+
http.server.requests: true # Гистограммы для перцентилей
148+
149+
prometheus:
150+
metrics:
151+
export:
152+
enabled: true # Включить экспорт метрик для Prometheus
153+
web:
154+
server:
155+
auto-time-requests: true # Должен быть здесь!
156+
157+
metrics:
158+
tags:
159+
application: ${spring.application.name} # Добавляет тег с именем приложения
160+
161+
162+
logging:
163+
structured:
164+
format:
165+
file: ecs
166+
console: ecs
167+
level:
168+
root: INFO

bot/src/test/java/backend/academy/bot/processor/UserMessageProcessorTest.java renamed to bot/src/test/java/backend/academy/bot/metrics/UserMessageProcessorTest.java

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
package backend.academy.bot.processor;
1+
package backend.academy.bot.metrics;
22

33
import static org.junit.jupiter.api.Assertions.*;
44
import static org.mockito.Mockito.*;
55

66
import backend.academy.bot.command.Command;
77
import backend.academy.bot.command.link.TrackCommand;
8-
import backend.academy.bot.state.UserState;
8+
import backend.academy.bot.processor.UserMessageProcessor;
99
import backend.academy.bot.state.UserStateManager;
1010
import com.pengrad.telegrambot.TelegramBot;
1111
import com.pengrad.telegrambot.model.Chat;
1212
import com.pengrad.telegrambot.model.Message;
1313
import com.pengrad.telegrambot.model.Update;
1414
import com.pengrad.telegrambot.request.SendMessage;
15+
import io.micrometer.core.instrument.Counter;
16+
import io.micrometer.core.instrument.MeterRegistry;
17+
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
1518
import java.util.List;
1619
import org.junit.jupiter.api.BeforeEach;
1720
import org.junit.jupiter.api.DisplayName;
@@ -34,50 +37,29 @@ public class UserMessageProcessorTest {
3437
private UserStateManager userStateManager;
3538

3639
private UserMessageProcessor userMessageProcessor;
40+
private MeterRegistry meterRegistry;
3741

3842
@BeforeEach
3943
void setUp() {
4044
MockitoAnnotations.openMocks(this);
41-
userMessageProcessor = new UserMessageProcessor(telegramBot, List.of(command1, trackCommand), userStateManager);
42-
}
43-
44-
@Test
45-
@DisplayName("Обработка сообщения: команда найдена и обработана")
46-
void testProcess_CommandFoundAndHandled() {
47-
Update update = createUpdateWithText("/mock");
48-
when(command1.matchesCommand(update)).thenReturn(true);
49-
when(command1.handle(update)).thenReturn(new SendMessage(123L, "Mock message"));
50-
51-
SendMessage result = userMessageProcessor.process(update);
52-
verify(command1, times(1)).matchesCommand(update);
53-
verify(command1, times(1)).handle(update);
54-
assertEquals("Mock message", result.getParameters().get("text"));
55-
}
56-
57-
@Test
58-
@DisplayName("Обработка сообщения: команда не найдена, состояние WAITING_URL")
59-
void testProcess_NoCommandFound_WaitingUrlState() {
60-
Update update = createUpdateWithText("https://github.com/example");
61-
when(command1.matchesCommand(update)).thenReturn(false);
62-
when(userStateManager.getUserState(123L)).thenReturn(UserState.WAITING_URL);
63-
when(trackCommand.handle(update)).thenReturn(new SendMessage(123L, "Track command handled"));
64-
65-
SendMessage result = userMessageProcessor.process(update);
66-
67-
verify(command1, times(1)).matchesCommand(update);
68-
verify(trackCommand, times(1)).handle(update);
69-
assertEquals("Track command handled", result.getParameters().get("text"));
45+
meterRegistry = new SimpleMeterRegistry(); // Используем реальный MeterRegistry
46+
userMessageProcessor =
47+
new UserMessageProcessor(telegramBot, List.of(command1, trackCommand), userStateManager, meterRegistry);
7048
}
7149

7250
@Test
7351
@DisplayName("Обработка сообщения: пользователь создается, если не существует")
7452
void testProcess_UserCreatedIfNotExist() {
7553
Update update = createUpdateWithText("/start");
7654
when(command1.matchesCommand(update)).thenReturn(true);
77-
when(command1.handle(update)).thenReturn(new SendMessage(123L, "User created"));
55+
when(command1.handle(update)).thenReturn(new SendMessage("123", "User created"));
7856

7957
userMessageProcessor.process(update);
8058

59+
// Проверяем метрику
60+
Counter counter = meterRegistry.counter("msg_count");
61+
assertEquals(1, counter.count());
62+
8163
verify(userStateManager, times(1)).createUserIfNotExist(123L);
8264
}
8365

@@ -89,8 +71,6 @@ private Update createUpdateWithText(String text) {
8971
when(update.message()).thenReturn(message);
9072
when(message.chat()).thenReturn(chat);
9173
when(chat.id()).thenReturn(123L);
92-
when(message.text()).thenReturn(text);
93-
9474
return update;
9575
}
9676
}

docker-compose.yaml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,83 @@ services:
104104
networks:
105105
- kafka-net
106106

107+
108+
prometheus:
109+
image: prom/prometheus:latest
110+
ports:
111+
- "9090:9090"
112+
volumes:
113+
- ./prometheus.yml:/etc/prometheus/prometheus.yml
114+
networks:
115+
- monitoring
116+
117+
grafana:
118+
image: grafana/grafana:latest
119+
ports:
120+
- "3000:3000"
121+
environment:
122+
- GF_SECURITY_ADMIN_USER=admin
123+
- GF_SECURITY_ADMIN_PASSWORD=admin
124+
networks:
125+
- monitoring
126+
127+
128+
bot:
129+
image: delphington/bot:latest
130+
# build:
131+
# context: ./bot
132+
# dockerfile: bot.Dockerfile
133+
container_name: bot
134+
restart: unless-stopped
135+
ports:
136+
- "8080:8080" # Проброс порта для доступа с хоста
137+
- "8090:8090" # Метрики
138+
environment:
139+
- TELEGRAM_TOKEN=${TELEGRAM_TOKEN}
140+
depends_on:
141+
- broker
142+
- redis
143+
networks:
144+
- backend
145+
- kafka-net # Чтобы видеть Kafka (broker:9092)
146+
147+
148+
# --- SCRAPPER ---
149+
scrapper:
150+
image: delphington/scrapper:latest
151+
# build:
152+
# context: ./scrapper
153+
# dockerfile: scrapper.Dockerfile
154+
container_name: scrapper
155+
restart: unless-stopped
156+
ports:
157+
- "8081:8081"
158+
- "8091:8091"
159+
environment:
160+
- GITHUB_TOKEN=${GITHUB_TOKEN} # Переменные из .env
161+
- SO_TOKEN_KEY=${SO_TOKEN_KEY}
162+
- SO_ACCESS_TOKEN=${SO_ACCESS_TOKEN}
163+
depends_on:
164+
- postgresql
165+
- broker
166+
- redis
167+
networks:
168+
- backend
169+
- kafka-net
170+
107171
volumes:
108172
postgresql:
109173
redis:
110174
zookeeper:
111175
broker:
176+
prometheus:
177+
grafana:
178+
112179

113180
networks:
114181
backend:
115182
driver: bridge
116183
kafka-net:
117184
driver: bridge
185+
monitoring:
186+
driver: bridge

prometheus.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
global:
2+
scrape_interval: 5s
3+
external_labels:
4+
monitor: 'codelab-monitor'
5+
6+
scrape_configs:
7+
- job_name: 'Bot'
8+
scrape_interval: 5s
9+
metrics_path: '/metrics'
10+
static_configs:
11+
- targets: ['host.docker.internal:8090']
12+
13+
- job_name: 'Scrapper'
14+
scrape_interval: 5s
15+
metrics_path: '/metrics'
16+
static_configs:
17+
- targets: ['host.docker.internal:8091']
18+
19+
20+
21+
22+
#scrape_configs:
23+
# - job_name: "prometheus" # Мониторинг самого Prometheus
24+
# static_configs:
25+
# - targets: ["localhost:9090"]
26+
#
27+
# - job_name: "bot" # Сервис bot на порту 8081
28+
# metrics_path: "/metrics" # Если используется Spring Boot Actuator
29+
# static_configs:
30+
# - targets: ["localhost:8081"]
31+
# labels:
32+
# service: "bot"
33+
#
34+
# - job_name: "scrapper" # Сервис scrapper на порту 8082 (если 8081 занят)
35+
# static_configs:
36+
# - targets: ["localhost:8082"]
37+
# labels:
38+
# service: "scrapper"

0 commit comments

Comments
 (0)