diff --git a/openapi.yaml b/openapi.yaml index 86ff751d4..6d860ba4f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1350,6 +1350,18 @@ paths: type: array items: $ref: '#/components/schemas/Statistics' + /metrics: + get: + summary: Fetch Prometheus Metrics + tags: + - Statistics + responses: + '200': + description: OK + content: + text/plain: + schema: + type: string /calendars: get: summary: Fetch a list of Calendars diff --git a/src/main/java/org/traccar/api/resource/MetricsResource.java b/src/main/java/org/traccar/api/resource/MetricsResource.java new file mode 100644 index 000000000..3f7a84bb8 --- /dev/null +++ b/src/main/java/org/traccar/api/resource/MetricsResource.java @@ -0,0 +1,55 @@ +package org.traccar.api.resource; + +import jakarta.annotation.security.PermitAll; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import org.traccar.api.BaseResource; +import org.traccar.database.StatisticsManager; +import org.traccar.model.Statistics; + +@Path("metrics") +@Produces(MediaType.TEXT_PLAIN) +public class MetricsResource extends BaseResource { + + @Inject + private StatisticsManager statisticsManager; + + @PermitAll + @GET + public String get() { + Statistics statistics = statisticsManager.getStatistics(); + StringBuilder sb = new StringBuilder(); + sb.append("# TYPE traccar_requests_total counter\n"); + sb.append("traccar_requests_total ").append(statistics.getRequests()).append('\n'); + sb.append("# TYPE traccar_messages_received_total counter\n"); + sb.append("traccar_messages_received_total ").append(statistics.getMessagesReceived()).append('\n'); + sb.append("# TYPE traccar_messages_stored_total counter\n"); + sb.append("traccar_messages_stored_total ").append(statistics.getMessagesStored()).append('\n'); + sb.append("# TYPE traccar_mail_sent_total counter\n"); + sb.append("traccar_mail_sent_total ").append(statistics.getMailSent()).append('\n'); + sb.append("# TYPE traccar_sms_sent_total counter\n"); + sb.append("traccar_sms_sent_total ").append(statistics.getSmsSent()).append('\n'); + sb.append("# TYPE traccar_geocoder_requests_total counter\n"); + sb.append("traccar_geocoder_requests_total ").append(statistics.getGeocoderRequests()).append('\n'); + sb.append("# TYPE traccar_geolocation_requests_total counter\n"); + sb.append("traccar_geolocation_requests_total ").append(statistics.getGeolocationRequests()).append('\n'); + sb.append("# TYPE traccar_active_users gauge\n"); + sb.append("traccar_active_users ").append(statistics.getActiveUsers()).append('\n'); + sb.append("# TYPE traccar_active_devices gauge\n"); + sb.append("traccar_active_devices ").append(statistics.getActiveDevices()).append('\n'); + if (statistics.getProtocols() != null) { + sb.append("# TYPE traccar_protocol_devices gauge\n"); + for (var entry : statistics.getProtocols().entrySet()) { + sb.append("traccar_protocol_devices{protocol=\"") + .append(entry.getKey()) + .append("\"} ") + .append(entry.getValue()) + .append('\n'); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index 5f4d97263..a70bf78fc 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -204,4 +204,27 @@ public class StatisticsManager { geolocationRequests += 1; } + public synchronized Statistics getStatistics() { + checkSplit(); + Statistics statistics = new Statistics(); + statistics.setCaptureTime(new Date()); + statistics.setActiveUsers(users.size()); + statistics.setActiveDevices(deviceProtocols.size()); + statistics.setRequests(requests); + statistics.setMessagesReceived(messagesReceived); + statistics.setMessagesStored(messagesStored); + statistics.setMailSent(mailSent); + statistics.setSmsSent(smsSent); + statistics.setGeocoderRequests(geocoderRequests); + statistics.setGeolocationRequests(geolocationRequests); + if (!deviceProtocols.isEmpty()) { + Map protocols = new HashMap<>(); + for (String protocol : deviceProtocols.values()) { + protocols.merge(protocol, (Integer) 1, Integer::sum); + } + statistics.setProtocols(protocols); + } + return statistics; + } + }