mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-06 13:19:47 -06:00
Export map tiles usage to Prometheus
This commit is contained in:
@@ -16,6 +16,13 @@ To set a custom tile URL, go to the user settings and set the `Maps` section to
|
||||
|
||||
- Safe settings for user with default values.
|
||||
- In the user settings, you can now set a custom tile URL for the map. #429 #715
|
||||
- If you have Prometheus exporter enabled, you can now see a `ruby_dawarich_map_tiles` metric in Prometheus, which shows the total number of map tiles loaded. Example:
|
||||
|
||||
```
|
||||
# HELP ruby_dawarich_map_tiles
|
||||
# TYPE ruby_dawarich_map_tiles gauge
|
||||
ruby_dawarich_map_tiles 99
|
||||
```
|
||||
|
||||
# 0.24.0 - 2025-02-10
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
prometheus_exporter: bundle exec prometheus_exporter -b ANY
|
||||
web: bin/rails server -p 3000 -b ::
|
||||
web: bin/rails server -p 3000 -b ::
|
||||
|
||||
@@ -28,6 +28,7 @@ Donate using crypto: [0x6bAd13667692632f1bF926cA9B421bEe7EaEB8D4](https://ethers
|
||||
- Explore statistics like the number of countries and cities visited, total distance traveled, and more!
|
||||
|
||||
📄 **Changelog**: Find the latest updates [here](CHANGELOG.md).
|
||||
|
||||
👩💻 **Contribute**: See [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute to Dawarich.
|
||||
---
|
||||
|
||||
|
||||
9
app/controllers/api/v1/tile_usages_controller.rb
Normal file
9
app/controllers/api/v1/tile_usages_controller.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::TileUsagesController < ApiController
|
||||
def create
|
||||
TileUsage::Track.new(params[:tile_count].to_i).call
|
||||
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
@@ -8,9 +8,7 @@ import { createMarkersArray } from "../maps/markers";
|
||||
import {
|
||||
createPolylinesLayer,
|
||||
updatePolylinesOpacity,
|
||||
updatePolylinesColors,
|
||||
calculateSpeed,
|
||||
getSpeedColor
|
||||
updatePolylinesColors
|
||||
} from "../maps/polylines";
|
||||
|
||||
import { fetchAndDrawAreas, handleAreaCreated } from "../maps/areas";
|
||||
@@ -32,9 +30,13 @@ import { countryCodesMap } from "../maps/country_codes";
|
||||
|
||||
import "leaflet-draw";
|
||||
import { initializeFogCanvas, drawFogCanvas, createFogOverlay } from "../maps/fog_of_war";
|
||||
import { TileMonitor } from "../maps/tile_monitor";
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["container"];
|
||||
static values = {
|
||||
monitoringEnabled: Boolean
|
||||
}
|
||||
|
||||
settingsButtonAdded = false;
|
||||
layerControl = null;
|
||||
@@ -245,6 +247,19 @@ export default class extends Controller {
|
||||
if (this.liveMapEnabled) {
|
||||
this.setupSubscription();
|
||||
}
|
||||
|
||||
// Initialize tile monitor
|
||||
this.tileMonitor = new TileMonitor(this.monitoringEnabledValue, this.apiKey);
|
||||
|
||||
// Add tile load event handlers to each base layer
|
||||
Object.entries(this.baseMaps()).forEach(([name, layer]) => {
|
||||
layer.on('tileload', () => {
|
||||
this.tileMonitor.recordTileLoad(name);
|
||||
});
|
||||
});
|
||||
|
||||
// Start monitoring
|
||||
this.tileMonitor.startMonitoring();
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
@@ -260,6 +275,11 @@ export default class extends Controller {
|
||||
if (this.map) {
|
||||
this.map.remove();
|
||||
}
|
||||
|
||||
// Stop tile monitoring
|
||||
if (this.tileMonitor) {
|
||||
this.tileMonitor.stopMonitoring();
|
||||
}
|
||||
}
|
||||
|
||||
setupSubscription() {
|
||||
|
||||
67
app/javascript/maps/tile_monitor.js
Normal file
67
app/javascript/maps/tile_monitor.js
Normal file
@@ -0,0 +1,67 @@
|
||||
export class TileMonitor {
|
||||
constructor(monitoringEnabled, apiKey) {
|
||||
this.monitoringEnabled = monitoringEnabled;
|
||||
this.apiKey = apiKey;
|
||||
this.tileQueue = 0;
|
||||
this.tileUpdateInterval = null;
|
||||
}
|
||||
|
||||
startMonitoring() {
|
||||
// Only start the interval if monitoring is enabled
|
||||
if (!this.monitoringEnabled) return;
|
||||
|
||||
// Clear any existing interval
|
||||
if (this.tileUpdateInterval) {
|
||||
clearInterval(this.tileUpdateInterval);
|
||||
}
|
||||
|
||||
// Set up a regular interval to send stats
|
||||
this.tileUpdateInterval = setInterval(() => {
|
||||
this.sendTileUsage();
|
||||
}, 5000); // Exactly every 5 seconds
|
||||
}
|
||||
|
||||
stopMonitoring() {
|
||||
if (this.tileUpdateInterval) {
|
||||
clearInterval(this.tileUpdateInterval);
|
||||
this.sendTileUsage(); // Send any remaining stats
|
||||
}
|
||||
}
|
||||
|
||||
recordTileLoad() {
|
||||
if (!this.monitoringEnabled) return;
|
||||
this.tileQueue += 1;
|
||||
}
|
||||
|
||||
sendTileUsage() {
|
||||
// Don't send if monitoring is disabled or queue is empty
|
||||
if (!this.monitoringEnabled || this.tileQueue === 0) return;
|
||||
|
||||
const currentCount = this.tileQueue;
|
||||
console.log('Sending tile usage batch:', currentCount);
|
||||
|
||||
fetch('/api/v1/tile_usages', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.apiKey}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
tile_count: currentCount
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
// Only subtract sent count if it hasn't changed
|
||||
if (this.tileQueue === currentCount) {
|
||||
this.tileQueue = 0;
|
||||
} else {
|
||||
this.tileQueue -= currentCount;
|
||||
}
|
||||
console.log('Tile usage batch sent successfully');
|
||||
})
|
||||
.catch(error => console.error('Error recording tile usage:', error));
|
||||
}
|
||||
}
|
||||
19
app/services/tile_usage/track.rb
Normal file
19
app/services/tile_usage/track.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class TileUsage::Track
|
||||
def initialize(count = 1)
|
||||
@count = count
|
||||
end
|
||||
|
||||
def call
|
||||
metric_data = {
|
||||
type: 'counter',
|
||||
name: 'dawarich_map_tiles',
|
||||
value: @count
|
||||
}
|
||||
|
||||
PrometheusExporter::Client.default.send_json(metric_data)
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("Failed to send tile usage metric: #{e.message}")
|
||||
end
|
||||
end
|
||||
@@ -53,6 +53,7 @@
|
||||
data-coordinates="<%= @coordinates %>"
|
||||
data-distance="<%= @distance %>"
|
||||
data-points_number="<%= @points_number %>"
|
||||
data-maps-monitoring-enabled-value="<%= DawarichSettings.prometheus_exporter_enabled? %>"
|
||||
data-timezone="<%= Rails.configuration.time_zone %>">
|
||||
<div data-maps-target="container" class="h-[25rem] rounded-lg w-full min-h-screen">
|
||||
<div id="fog" class="fog"></div>
|
||||
|
||||
@@ -3,10 +3,25 @@
|
||||
<div class="min-h-content w-full my-5">
|
||||
<%= render 'settings/navigation' %>
|
||||
|
||||
<div class="flex justify-between items-center mt-5">
|
||||
<div class="flex justify-between items-center my-5">
|
||||
<h1 class="font-bold text-4xl">Maps settings</h1>
|
||||
</div>
|
||||
|
||||
<div role="alert" class="alert alert-info">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 shrink-0 stroke-current">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<span>Please remember, that using a custom tile URL may result in extra costs. Check your map tile provider's terms of service for more information.</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-5" data-controller="map-preview">
|
||||
<%= form_for :maps,
|
||||
url: settings_maps_path,
|
||||
|
||||
@@ -18,12 +18,11 @@ class DawarichSettings
|
||||
@geoapify_enabled ||= GEOAPIFY_API_KEY.present?
|
||||
end
|
||||
|
||||
def meters_between_tracks
|
||||
@meters_between_tracks ||= 300
|
||||
end
|
||||
|
||||
def minutes_between_tracks
|
||||
@minutes_between_tracks ||= 20
|
||||
def prometheus_exporter_enabled?
|
||||
@prometheus_exporter_enabled ||=
|
||||
ENV['PROMETHEUS_EXPORTER_ENABLED'].to_s == 'true' &&
|
||||
ENV['PROMETHEUS_EXPORTER_HOST'].present? &&
|
||||
ENV['PROMETHEUS_EXPORTER_PORT'].present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
if !Rails.env.test? && ENV['PROMETHEUS_EXPORTER_ENABLED'].to_s == 'true'
|
||||
if !Rails.env.test? && DawarichSettings.prometheus_exporter_enabled?
|
||||
require 'prometheus_exporter/middleware'
|
||||
require 'prometheus_exporter/instrumentation'
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ Rails.application.routes.draw do
|
||||
get 'thumbnail', constraints: { id: %r{[^/]+} }
|
||||
end
|
||||
end
|
||||
|
||||
resources :tile_usages, only: [:create]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user