feat: testing metrics

This commit is contained in:
Alejandro Matos
2026-03-20 00:04:16 -05:00
parent 7026740ccd
commit 060a790d0b
3 changed files with 178 additions and 0 deletions
@@ -0,0 +1,113 @@
package com.restcountries.log;
import io.micronaut.scheduling.annotation.Scheduled;
import jakarta.inject.Singleton;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicLong;
@Singleton
public class MetricsLogger {
private final RequestCounter counter;
private final AtomicLong globalCounter = new AtomicLong(0);
private final AtomicLong dailyCounter = new AtomicLong(0);
private LocalDate currentDay = LocalDate.now();
public MetricsLogger(RequestCounter counter) {
this.counter = counter;
}
@Scheduled(fixedRate = "6h")
void logStats() {
long requests = counter.getTotalRequests();
if (requests == 0) {
return;
}
long totalRequests = globalCounter.addAndGet(requests);
dailyCounter.addAndGet(requests);
int windowMinutes = 360;
double avgRps = requests / (windowMinutes * 60.0);
LocalDateTime now = LocalDateTime.now();
writeLine(
now,
windowMinutes,
requests,
totalRequests,
avgRps,
""
);
counter.reset();
checkDailySummary(now);
}
private void checkDailySummary(LocalDateTime now) {
LocalDate today = now.toLocalDate();
if (!today.equals(currentDay)) {
writeDailySummary();
dailyCounter.set(0);
currentDay = today;
}
}
private void writeDailySummary() {
long dailyTotal = dailyCounter.get();
double avgRps = dailyTotal / 86400.0; // 24h
LocalDateTime endOfDay = currentDay.atTime(23, 59, 59);
writeLine(
endOfDay,
1440,
dailyTotal,
null,
avgRps,
"DAILY_SUMMARY"
);
}
private void writeLine(
LocalDateTime timestamp,
int windowMinutes,
Long requests,
Long totalRequests,
double avgRps,
String notes
) {
String line = String.join(",",
timestamp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
String.valueOf(windowMinutes),
String.valueOf(requests),
totalRequests != null ? String.valueOf(totalRequests) : "",
String.format("%.2f", avgRps),
notes
) + "\n";
File file = new File("/tmp/request-stats.csv");
boolean writeHeader = !file.exists();
try (FileWriter fw = new FileWriter(file, true)) {
if (writeHeader) {
fw.write("timestamp,window_minutes,requests,total_requests,avg_rps,notes\n");
}
fw.write(line);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,43 @@
package com.restcountries.log;
import jakarta.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Singleton
public class RequestCounter {
private final AtomicLong totalRequests = new AtomicLong(0);
private final ConcurrentHashMap<String, AtomicLong> endpointCounts = new ConcurrentHashMap<>();
public void increment(String path) {
totalRequests.incrementAndGet();
endpointCounts
.computeIfAbsent(path, k -> new AtomicLong(0))
.incrementAndGet();
}
public long getTotalRequests() {
return totalRequests.get();
}
public ConcurrentHashMap<String, AtomicLong> getEndpointCounts() {
return endpointCounts;
}
public List<Map.Entry<String, Long>> getTopEndpoints() {
return endpointCounts.entrySet()
.stream()
.map(e -> Map.entry(e.getKey(), e.getValue().get()))
.sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) // DESC
.toList();
}
public void reset() {
totalRequests.set(0);
endpointCounts.clear();
}
}
@@ -0,0 +1,22 @@
package com.restcountries.log;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.MutableHttpResponse;
import io.micronaut.http.annotation.Filter;
import io.micronaut.http.filter.HttpServerFilter;
import io.micronaut.http.filter.ServerFilterChain;
import jakarta.inject.Inject;
import org.reactivestreams.Publisher;
@Filter("/**")
public class RequestLoggingFilter implements HttpServerFilter {
@Inject
RequestCounter counter;
@Override
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
counter.increment(request.getPath());
return chain.proceed(request);
}
}