Repository: airbrake/pybrake

Issue:
Change api to accept end time
Instead of `time=, ms=` it should accept `start_time=, end_time=`

Discussion:

Patch:
diff --git a/examples/flask/airbrake_middleware.py b/examples/flask/airbrake_middleware.py
index 24e3ea1..07ebd47 100755
--- a/examples/flask/airbrake_middleware.py
+++ b/examples/flask/airbrake_middleware.py
@@ -1,4 +1,4 @@
-import datetime
+import time
 from flask import g, request
 from pybrake.utils import logger
 
@@ -8,26 +8,19 @@ def setup_airbrake_middleware(app, notifier):
 
 def before_request():
   def before_request_middleware():
-    g.flask_request_start_time = datetime.datetime.now()
+    g.request_start_time = time.time()
 
   return before_request_middleware
 
 def after_request(notifier):
   def after_request_middleware(response):
-    if not hasattr(g, 'flask_request_start_time'):
-      logger.error("flask_request_start_time is empty")
-      return response
-
-    now = datetime.datetime.utcnow()
-    dur = now - g.flask_request_start_time
-    if dur == 0:
-      logger.error("processing time is not valid")
+    if not hasattr(g, 'request_start_time'):
+      logger.error("request_start_time is empty")
       return response
 
     notifier.notify_request(
-      method=request.method, route=str(request.endpoint),
-      status_code=response.status_code, time=now, ms=dur.millisecond,
-    )
+      method=request.method, route=str(request.endpoint), status_code=response.status_code,
+      start_time=g.request_start_time, end_time=time.time())
 
     return response
 
diff --git a/pybrake/routes.py b/pybrake/routes.py
index 21a14da..92a199d 100755
--- a/pybrake/routes.py
+++ b/pybrake/routes.py
@@ -1,5 +1,6 @@
 import base64
 import json
+from datetime import datetime
 from threading import Lock, Timer
 from tdigest import TDigest
 import requests
@@ -33,7 +34,7 @@ class RouteStat():
     self.count = 0
     self.sum = 0
     self.sumsq = 0
-    self.time = time.replace(second=0, microsecond=0).strftime('%Y-%m-%dT%H:%M:%SZ')
+    self.time = time_to_str(time)
     self.td = TDigest()
     self.tdigest = None
 
@@ -75,19 +76,24 @@ class RouteStats():
     stats_json = json.dumps({"routes": [stat.__dict__ for _, stat in stats.items()]})
     requests.post(self._api_url, data=stats_json, headers=self._airbrake_headers)
 
-  def notify_request(self, method='', route='', status_code=0, time=None, ms=0):
+  def notify_request(self, method='', route='', status_code=0, start_time=None, end_time=None):
     self._init()
 
-    statKey = route_stat_key(method, route, status_code, time)
+    statKey = route_stat_key(method, route, status_code, start_time)
     with self._lock:
       if statKey in self._stats:
         stat = self._stats.get(statKey)
       else:
-        stat = RouteStat(method=method, route=route, status_code=status_code, time=time)
+        stat = RouteStat(method=method, route=route, status_code=status_code, time=start_time)
         self._stats[statKey] = stat
 
+      ms = round((end_time - start_time) * 1000, 2)
       stat.add(ms)
 
+def time_to_str(time):
+  t = datetime.utcfromtimestamp(time).replace(second=0, microsecond=0)
+  return t.strftime('%Y-%m-%dT%H:%M:%SZ')
+
 def route_stat_key(method='', route='', status_code=0, time=None):
-  tm = time.replace(second=0, microsecond=0).strftime('%Y-%m-%dT%H:%M:%SZ')
-  return "{}:{}:{}:{}".format(method, route, status_code, tm)
+  time = time // 60 * 60
+  return "{}:{}:{}:{}".format(method, route, status_code, time)


Test patch:
diff --git a/pybrake/test_routes.py b/pybrake/test_routes.py
index c54c3c0..d55aa48 100644
--- a/pybrake/test_routes.py
+++ b/pybrake/test_routes.py
@@ -1,4 +1,4 @@
-from datetime import datetime
+import calendar
 import json
 import requests_mock
 
@@ -16,10 +16,11 @@ def test_route_stat():
     url = "http://test.com/api/v5/projects/1/routes-stats"
     m.post(url, json=_request_callback)
 
-    tm = datetime(2000, 1, 1, 0, 0)
-    route_stats.notify_request("GET", "ping", 200, tm, 123)
-    route_stats.notify_request("GET", "pong", 200, tm, 123)
-    route_stats.notify_request("GET", "pong", 200, tm, 123)
+    start_time = calendar.timegm((2000, 1, 1, 0, 0, 0, 0, 0, 0))
+    end_time = start_time + 0.123
+    route_stats.notify_request("GET", "ping", 200, start_time, end_time)
+    route_stats.notify_request("GET", "pong", 200, start_time, end_time)
+    route_stats.notify_request("GET", "pong", 200, start_time, end_time)
 
     route_stats._thread.join()
     assert m.call_count == 1