mirror of
https://gitlab.com/restcountries/restcountries.git
synced 2026-03-31 15:07:46 +01:00
feat: testing metrics
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user