Skip to content

Commit 0b4b589

Browse files
committed
Fix TimeGenerated in azure log analytics store
Conversion to UTC Always remove the TZ Better millisecond rounding
1 parent 2bc7fb9 commit 0b4b589

File tree

2 files changed

+53
-18
lines changed

2 files changed

+53
-18
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from dateutil import parser
2+
from django.test import SimpleTestCase
3+
from zentral.core.stores.backends.azure_log_analytics import datetime_to_iso8601z_truncated_to_milliseconds
4+
5+
6+
class TestDateTimeConverstion(SimpleTestCase):
7+
def _assert_ts_equals(self, ts_list):
8+
for in_ts, out_ts in ts_list:
9+
self.assertEqual(
10+
datetime_to_iso8601z_truncated_to_milliseconds(parser.parse(in_ts)),
11+
out_ts
12+
)
13+
14+
def test_timezone_conversion(self):
15+
self._assert_ts_equals((
16+
("2019-01-12T11:11:11.319+02:00", "2019-01-12T09:11:11.319Z"),
17+
("2019-01-12T11:11:11.319+00:00", "2019-01-12T11:11:11.319Z"),
18+
("2019-01-12T11:11:11Z", "2019-01-12T11:11:11Z"),
19+
))
20+
21+
def test_microseconds_to_milliseconds(self):
22+
self._assert_ts_equals((
23+
("2019-01-12T11:11:11.999999", "2019-01-12T11:11:12Z"),
24+
("2019-01-12T11:11:11.123111", "2019-01-12T11:11:11.123Z"),
25+
("2019-01-12T11:11:11.000999+00:00", "2019-01-12T11:11:11.001Z"),
26+
("2019-01-12T11:11:11.000234+00:00", "2019-01-12T11:11:11Z"),
27+
))

zentral/core/stores/backends/azure_log_analytics.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import base64
22
import collections.abc
3-
from datetime import datetime
3+
from datetime import datetime, timedelta
44
import hashlib
55
import hmac
66
import json
77
import logging
8+
import pytz
89
import requests
910
from zentral.core.events import event_from_event_d
1011
from zentral.core.stores.backends.base import BaseEventStore
@@ -13,6 +14,28 @@
1314
logger = logging.getLogger('zentral.core.stroes.backends.azure_log_analytics')
1415

1516

17+
def datetime_to_iso8601z_truncated_to_milliseconds(dt):
18+
# round created at to milliseconds
19+
dt_microsecond = dt.microsecond
20+
if dt_microsecond:
21+
dt_millisecond = round(dt_microsecond / 1000)
22+
if dt_millisecond == 1000:
23+
dt = dt.replace(microsecond=0)
24+
dt += timedelta(seconds=1)
25+
else:
26+
dt = dt.replace(microsecond=1000 * dt_millisecond)
27+
28+
# convert created at to UTC, remove the TZ info (naive datetime), convert to isoformat
29+
dt_iso = dt.astimezone(pytz.utc).replace(tzinfo=None).isoformat()
30+
31+
# truncate the microseconds in isoformat if necessary
32+
if "." in dt_iso:
33+
dt_iso = dt_iso[:-3]
34+
35+
# add the pseudo time zone
36+
return "{}Z".format(dt_iso)
37+
38+
1639
class EventStore(BaseEventStore):
1740
log_type = "ZentralEvent"
1841
content_type = "application/json"
@@ -53,23 +76,8 @@ def _prepare_event(self, event):
5376

5477
metadata = event_d.pop("_zentral")
5578

56-
# created at
57-
created_at = metadata.pop("created_at")
58-
if "." in created_at:
59-
created_at, created_at_ms = created_at.split(".")
60-
if len(created_at_ms) == 6:
61-
created_at_ms = round(int(created_at_ms) / 1000)
62-
elif len(created_at_ms) == 3:
63-
created_at_ms = int(created_at_ms)
64-
else:
65-
# TODO
66-
created_at_ms = 0
67-
if created_at_ms:
68-
if created_at_ms == 1000:
69-
# TODO
70-
created_at_ms = 999
71-
created_at = "{}.{:03d}".format(created_at, created_at_ms)
72-
metadata["created_at"] = "{}Z".format(created_at)
79+
# fix created_at format for use as TimeGenerated field via the time-generated-field header
80+
metadata["created_at"] = datetime_to_iso8601z_truncated_to_milliseconds(event.metadata.created_at)
7381

7482
# flatten the metadata
7583
azure_event = self._flatten_metadata(metadata)

0 commit comments

Comments
 (0)