mirror of
https://github.com/tcivie/meshtastic-metrics-exporter.git
synced 2025-03-05 20:52:02 -08:00
Bug fixes: Changed Histograms to Gages and updated the dashboards
This commit is contained in:
parent
3cfadccc27
commit
0b487336fb
2
.env
2
.env
|
@ -13,7 +13,7 @@ MQTT_PORT=1883
|
||||||
MQTT_USERNAME=meshdev
|
MQTT_USERNAME=meshdev
|
||||||
MQTT_PASSWORD=large4cats
|
MQTT_PASSWORD=large4cats
|
||||||
MQTT_KEEPALIVE=60
|
MQTT_KEEPALIVE=60
|
||||||
MQTT_TOPIC='msh/israel/#'
|
MQTT_TOPIC='msh/#'
|
||||||
MQTT_IS_TLS=false
|
MQTT_IS_TLS=false
|
||||||
|
|
||||||
# MQTT protocol version (default: MQTTv5) the public MQTT server supports MQTTv311
|
# MQTT protocol version (default: MQTTv5) the public MQTT server supports MQTTv311
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,5 @@
|
||||||
|
CREATE EXTENSION IF NOT EXISTS moddatetime;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS messages
|
CREATE TABLE IF NOT EXISTS messages
|
||||||
(
|
(
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
|
@ -29,13 +31,10 @@ CREATE TABLE IF NOT EXISTS node_details
|
||||||
role VARCHAR,
|
role VARCHAR,
|
||||||
mqtt_status VARCHAR default 'none',
|
mqtt_status VARCHAR default 'none',
|
||||||
-- Location Data
|
-- Location Data
|
||||||
longitude FLOAT,
|
longitude INT,
|
||||||
latitude FLOAT,
|
latitude INT,
|
||||||
altitude FLOAT,
|
altitude INT,
|
||||||
precision FLOAT,
|
precision INT,
|
||||||
country VARCHAR,
|
|
||||||
city VARCHAR,
|
|
||||||
state VARCHAR,
|
|
||||||
-- SQL Data
|
-- SQL Data
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||||
|
|
|
@ -12,7 +12,7 @@ except ImportError:
|
||||||
from meshtastic.protobuf.mesh_pb2 import MeshPacket, Data, HardwareModel
|
from meshtastic.protobuf.mesh_pb2 import MeshPacket, Data, HardwareModel
|
||||||
from meshtastic.protobuf.portnums_pb2 import PortNum
|
from meshtastic.protobuf.portnums_pb2 import PortNum
|
||||||
|
|
||||||
from prometheus_client import CollectorRegistry, Counter, Histogram, Gauge
|
from prometheus_client import CollectorRegistry, Counter, Gauge
|
||||||
from psycopg_pool import ConnectionPool
|
from psycopg_pool import ConnectionPool
|
||||||
|
|
||||||
from exporter.client_details import ClientDetails
|
from exporter.client_details import ClientDetails
|
||||||
|
@ -46,10 +46,14 @@ class MessageProcessor:
|
||||||
'destination_role'
|
'destination_role'
|
||||||
]
|
]
|
||||||
|
|
||||||
self.message_size_in_bytes = Histogram(
|
reduced_labels = [
|
||||||
|
'source_id', 'destination_id'
|
||||||
|
]
|
||||||
|
|
||||||
|
self.message_size_in_bytes = Gauge(
|
||||||
'text_message_app_size_in_bytes',
|
'text_message_app_size_in_bytes',
|
||||||
'Size of text messages processed by the app in Bytes',
|
'Size of text messages processed by the app in Bytes',
|
||||||
common_labels + ['portnum'],
|
reduced_labels + ['portnum'],
|
||||||
registry=self.registry
|
registry=self.registry
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -74,7 +78,7 @@ class MessageProcessor:
|
||||||
registry=self.registry
|
registry=self.registry
|
||||||
)
|
)
|
||||||
# Histogram for the rx_time (time in seconds)
|
# Histogram for the rx_time (time in seconds)
|
||||||
self.rx_time_histogram = Histogram(
|
self.rx_time_histogram = Gauge(
|
||||||
'mesh_packet_rx_time',
|
'mesh_packet_rx_time',
|
||||||
'Receive time of mesh packets (seconds since 1970)',
|
'Receive time of mesh packets (seconds since 1970)',
|
||||||
common_labels,
|
common_labels,
|
||||||
|
@ -205,10 +209,15 @@ class MessageProcessor:
|
||||||
'destination_role': destination_client_details.role,
|
'destination_role': destination_client_details.role,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reduced_labels = {
|
||||||
|
'source_id': source_client_details.node_id,
|
||||||
|
'destination_id': destination_client_details.node_id
|
||||||
|
}
|
||||||
|
|
||||||
self.message_size_in_bytes.labels(
|
self.message_size_in_bytes.labels(
|
||||||
**common_labels,
|
**reduced_labels,
|
||||||
portnum=self.get_port_name_from_portnum(port_num)
|
portnum=self.get_port_name_from_portnum(port_num)
|
||||||
).observe(sys.getsizeof(mesh_packet))
|
).set(sys.getsizeof(mesh_packet))
|
||||||
|
|
||||||
self.source_message_type_counter.labels(
|
self.source_message_type_counter.labels(
|
||||||
**common_labels,
|
**common_labels,
|
||||||
|
@ -226,7 +235,7 @@ class MessageProcessor:
|
||||||
|
|
||||||
self.rx_time_histogram.labels(
|
self.rx_time_histogram.labels(
|
||||||
**common_labels
|
**common_labels
|
||||||
).observe(mesh_packet.rx_time)
|
).set(mesh_packet.rx_time)
|
||||||
|
|
||||||
self.rx_snr_gauge.labels(
|
self.rx_snr_gauge.labels(
|
||||||
**common_labels
|
**common_labels
|
||||||
|
|
|
@ -167,7 +167,7 @@ class NodeInfoAppProcessor(Processor):
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
self.metrics.db.execute_db_operation(db_operation)
|
self.metrics.get_db().execute_db_operation(db_operation)
|
||||||
|
|
||||||
|
|
||||||
@ProcessorRegistry.register_processor(PortNum.ROUTING_APP)
|
@ProcessorRegistry.register_processor(PortNum.ROUTING_APP)
|
||||||
|
@ -499,24 +499,8 @@ class NeighborInfoAppProcessor(Processor):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to parse NEIGHBORINFO_APP packet: {e}")
|
logger.error(f"Failed to parse NEIGHBORINFO_APP packet: {e}")
|
||||||
return
|
return
|
||||||
self.update_node_graph(neighbor_info, client_details)
|
|
||||||
self.update_node_neighbors(neighbor_info, client_details)
|
self.update_node_neighbors(neighbor_info, client_details)
|
||||||
|
|
||||||
def update_node_graph(self, neighbor_info: NeighborInfo, client_details: ClientDetails):
|
|
||||||
def operation(cur, conn):
|
|
||||||
cur.execute("""
|
|
||||||
INSERT INTO node_graph (node_id, last_sent_by_node_id, broadcast_interval_secs)
|
|
||||||
VALUES (%s, %s, %s)
|
|
||||||
ON CONFLICT (node_id)
|
|
||||||
DO UPDATE SET
|
|
||||||
last_sent_by_node_id = EXCLUDED.last_sent_by_node_id,
|
|
||||||
broadcast_interval_secs = EXCLUDED.broadcast_interval_secs,
|
|
||||||
last_sent_at = CURRENT_TIMESTAMP
|
|
||||||
""", (client_details.node_id, neighbor_info.last_sent_by_id, neighbor_info.node_broadcast_interval_secs))
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
self.metrics.db.execute_db_operation(operation)
|
|
||||||
|
|
||||||
def update_node_neighbors(self, neighbor_info: NeighborInfo, client_details: ClientDetails):
|
def update_node_neighbors(self, neighbor_info: NeighborInfo, client_details: ClientDetails):
|
||||||
def operation(cur, conn):
|
def operation(cur, conn):
|
||||||
new_neighbor_ids = [str(neighbor.node_id) for neighbor in neighbor_info.neighbors]
|
new_neighbor_ids = [str(neighbor.node_id) for neighbor in neighbor_info.neighbors]
|
||||||
|
@ -549,7 +533,7 @@ class NeighborInfoAppProcessor(Processor):
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
self.metrics.db.execute_db_operation(operation)
|
self.metrics.get_db().execute_db_operation(operation)
|
||||||
|
|
||||||
|
|
||||||
@ProcessorRegistry.register_processor(PortNum.ATAK_PLUGIN)
|
@ProcessorRegistry.register_processor(PortNum.ATAK_PLUGIN)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import geopy.point
|
import uuid
|
||||||
|
|
||||||
from geopy.geocoders import Nominatim
|
from geopy.geocoders import Nominatim
|
||||||
from prometheus_client import CollectorRegistry, Counter, Gauge
|
from prometheus_client import CollectorRegistry, Counter, Gauge
|
||||||
|
|
||||||
|
@ -19,8 +20,11 @@ class _Metrics:
|
||||||
self._registry = registry
|
self._registry = registry
|
||||||
self._init_metrics()
|
self._init_metrics()
|
||||||
self.initialized = True # Attribute to indicate initialization
|
self.initialized = True # Attribute to indicate initialization
|
||||||
self.geolocator = Nominatim()
|
self.geolocator = Nominatim(user_agent=f"meshtastic-prometheus-exporter-{str(uuid.uuid4())}")
|
||||||
self.db = db
|
self.db = db
|
||||||
|
|
||||||
|
def get_db(self):
|
||||||
|
return self.db
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_common_labels():
|
def _get_common_labels():
|
||||||
|
@ -36,22 +40,24 @@ class _Metrics:
|
||||||
self._init_route_discovery_metrics()
|
self._init_route_discovery_metrics()
|
||||||
|
|
||||||
def update_metrics_position(self, latitude, longitude, altitude, precision, client_details: ClientDetails):
|
def update_metrics_position(self, latitude, longitude, altitude, precision, client_details: ClientDetails):
|
||||||
point = geopy.point.Point(latitude, longitude, altitude)
|
# Could be used to calculate more complex data (Like distances etc..)
|
||||||
location = self.geolocator.reverse(point, language='en')
|
# point = geopy.point.Point(latitude, longitude, altitude) # Not used for now
|
||||||
|
|
||||||
country = location.raw.get('address', {}).get('country', 'Unknown')
|
if latitude != 0 and longitude != 0:
|
||||||
city = location.raw.get('address', {}).get('city', 'Unknown')
|
# location = RateLimiter(self.geolocator.reverse, min_delay_seconds=10, swallow_exceptions=False)((latitude, longitude), language='en', timeout=10)
|
||||||
state = location.raw.get('address', {}).get('state', 'Unknown')
|
# country = location.raw.get('address', {}).get('country', 'Unknown')
|
||||||
|
# city = location.raw.get('address', {}).get('city', 'Unknown')
|
||||||
|
# state = location.raw.get('address', {}).get('state', 'Unknown')
|
||||||
|
|
||||||
def db_operation(cur, conn):
|
def db_operation(cur, conn):
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
UPDATE node_details
|
UPDATE node_details
|
||||||
SET latitude = %s, longitude = %s, altitude = %s, precision = %s, country = %s, city = %s, state = %s
|
SET latitude = %s, longitude = %s, altitude = %s, precision = %s
|
||||||
WHERE node_id = %s
|
WHERE node_id = %s
|
||||||
""", (latitude, longitude, altitude, precision, country, city, state, client_details.node_id))
|
""", (latitude, longitude, altitude, precision, client_details.node_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
self.db.execute_db_operation(db_operation)
|
self.db.execute_db_operation(db_operation)
|
||||||
|
|
||||||
def _init_metrics_telemetry_power(self):
|
def _init_metrics_telemetry_power(self):
|
||||||
self.ch1_voltage_gauge = Gauge(
|
self.ch1_voltage_gauge = Gauge(
|
||||||
|
|
|
@ -6,4 +6,5 @@ cryptography~=42.0.8
|
||||||
psycopg~=3.1.19
|
psycopg~=3.1.19
|
||||||
psycopg_pool~=3.2.2
|
psycopg_pool~=3.2.2
|
||||||
meshtastic~=2.3.13
|
meshtastic~=2.3.13
|
||||||
psycopg-binary~=3.1.20
|
psycopg-binary~=3.1.20
|
||||||
|
geopy>=2.4.1
|
Loading…
Reference in a new issue