33import base64
44import logging
55import re
6+ from enum import Enum
67
78from six import iteritems
89
2627DEFAULT_INFLUX_PASSWORD = None
2728DEFAULT_INFLUX_PROTOCOL = "http"
2829
30+ class ReportingPrecision (Enum ):
31+ HOURS = "h"
32+ MINUTES = "m"
33+ SECONDS = "s"
34+ MILLISECONDS = "ms"
35+ MICROSECONDS = "u"
36+ NANOSECONDS = "ns"
37+
2938
3039class InfluxReporter (Reporter ):
3140 """
@@ -47,7 +56,13 @@ def __init__(
4756 autocreate_database = False ,
4857 clock = None ,
4958 global_tags = None ,
59+ reporting_precision = ReportingPrecision .SECONDS
5060 ):
61+ """
62+ :param reporting_precision: The precision in which the reporter reports to influx.
63+ The default is seconds. This is a tradeoff between precision and performance. More
64+ coarse precision may result in significant improvements in compression and vice versa.
65+ """
5166 super (InfluxReporter , self ).__init__ (registry , reporting_interval , clock )
5267 self .prefix = prefix
5368 self .database = database
@@ -64,6 +79,8 @@ def __init__(
6479 else :
6580 self .global_tags = global_tags
6681
82+ self .reporting_precision = reporting_precision
83+
6784 def _create_database (self ):
6885 url = "%s://%s:%s/query" % (self .protocol , self .server , self .port )
6986 q = quote ("CREATE DATABASE %s" % self .database )
@@ -87,10 +104,14 @@ def _create_database(self):
87104 def report_now (self , registry = None , timestamp = None ):
88105 if self .autocreate_database and not self ._did_create_database :
89106 self ._create_database ()
90- timestamp = timestamp or int (round (self .clock .time ()))
107+ timestamp = timestamp or self .clock .time ()
108+ timestamp_in_reporting_precision = _to_timestamp_in_precision (
109+ timestamp = timestamp ,
110+ precision = self .reporting_precision
111+ )
91112 metrics = (registry or self .registry ).dump_metrics (key_is_metric = True )
92113
93- influx_lines = self ._get_influx_protocol_lines (metrics , timestamp )
114+ influx_lines = self ._get_influx_protocol_lines (metrics , timestamp_in_reporting_precision )
94115 # If you don't have anything nice to say than don't say nothing
95116 if influx_lines :
96117 post_data = "\n " .join (influx_lines )
@@ -120,11 +141,15 @@ def _get_influx_protocol_lines(self, metrics, timestamp):
120141 for event in metric_values .get ("events" , []):
121142 values = InfluxReporter ._stringify_values (event .values )
122143
144+ event_timestamp = _to_timestamp_in_precision (
145+ timestamp = event .time ,
146+ precision = self .reporting_precision
147+ )
123148 line = "%s%s %s %s" % (
124149 table ,
125150 tags ,
126151 values ,
127- int ( round ( event . time ))
152+ event_timestamp
128153 )
129154
130155 lines .append (line )
@@ -160,7 +185,7 @@ def _stringify_tags(self, metric):
160185 return ""
161186
162187 def _get_url (self ):
163- path = "/write?db=%s&precision=s" % self .database
188+ path = "/write?db=%s&precision=% s" % ( self .database , self . reporting_precision . value )
164189 return "%s://%s:%s%s" % (self .protocol , self .server , self .port , path )
165190
166191 def _add_auth_data (self , request ):
@@ -186,6 +211,27 @@ def _try_send(self, url, data):
186211 response
187212 )
188213
214+ def _to_timestamp_in_precision (timestamp : float , precision : ReportingPrecision ) -> int :
215+ if precision == ReportingPrecision .HOURS :
216+ return int (timestamp / 60 / 60 )
217+
218+ if precision == ReportingPrecision .MINUTES :
219+ return int (timestamp / 60 )
220+
221+ if precision == ReportingPrecision .SECONDS :
222+ return int (timestamp )
223+
224+ if precision == ReportingPrecision .MILLISECONDS :
225+ return int (timestamp * 1e3 )
226+
227+ if precision == ReportingPrecision .MICROSECONDS :
228+ return int (timestamp * 1e6 )
229+
230+ if precision == ReportingPrecision .NANOSECONDS :
231+ return int (timestamp * 1e9 )
232+
233+ raise Exception ("Unsupported ReportingPrecision" )
234+
189235
190236def _format_field_value (value ):
191237 if isinstance (value , MarkInt ):
0 commit comments