diff --git a/CHANGELOG.md b/CHANGELOG.md index 592bcffe83..ec23a21e6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ ### Bug fixes +* Increase breadcrumb time precision to milliseconds + [#954](https://github.com/bugsnag/bugsnag-android/pull/954) + +## TBD + +### Bug fixes + * Avoid crash when initializing bugsnag in attachBaseContext [#953](https://github.com/bugsnag/bugsnag-android/pull/953) diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/DateUtils.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/DateUtils.java index ff6cdab163..406e16d19b 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/DateUtils.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/DateUtils.java @@ -16,7 +16,7 @@ class DateUtils { @Override protected DateFormat initialValue() { TimeZone tz = TimeZone.getTimeZone("UTC"); - DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); + DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); iso8601.setTimeZone(tz); return iso8601; } diff --git a/bugsnag-android-core/src/test/resources/breadcrumb_serialization_0.json b/bugsnag-android-core/src/test/resources/breadcrumb_serialization_0.json index 4539593035..54e639e08f 100644 --- a/bugsnag-android-core/src/test/resources/breadcrumb_serialization_0.json +++ b/bugsnag-android-core/src/test/resources/breadcrumb_serialization_0.json @@ -1,5 +1,5 @@ { - "timestamp": "1970-01-01T00:00:00Z", + "timestamp": "1970-01-01T00:00:00.000Z", "name": "helloworld", "type": "manual", "metaData": {} diff --git a/bugsnag-android-core/src/test/resources/breadcrumb_serialization_1.json b/bugsnag-android-core/src/test/resources/breadcrumb_serialization_1.json index b5af851693..6df6abe4ed 100644 --- a/bugsnag-android-core/src/test/resources/breadcrumb_serialization_1.json +++ b/bugsnag-android-core/src/test/resources/breadcrumb_serialization_1.json @@ -1,5 +1,5 @@ { - "timestamp": "1970-01-01T00:00:00Z", + "timestamp": "1970-01-01T00:00:00.000Z", "name": "metadata", "type": "process", "metaData": { diff --git a/bugsnag-android-core/src/test/resources/breadcrumb_state_serialization_0.json b/bugsnag-android-core/src/test/resources/breadcrumb_state_serialization_0.json index f5c28396c6..6151953caa 100644 --- a/bugsnag-android-core/src/test/resources/breadcrumb_state_serialization_0.json +++ b/bugsnag-android-core/src/test/resources/breadcrumb_state_serialization_0.json @@ -1,6 +1,6 @@ [ { - "timestamp": "1970-01-01T00:00:00Z", + "timestamp": "1970-01-01T00:00:00.000Z", "name": "helloworld", "type": "manual", "metaData": { diff --git a/bugsnag-android-core/src/test/resources/device_data_serialization_1.json b/bugsnag-android-core/src/test/resources/device_data_serialization_1.json index 58b6d874f9..d179e37ffa 100644 --- a/bugsnag-android-core/src/test/resources/device_data_serialization_1.json +++ b/bugsnag-android-core/src/test/resources/device_data_serialization_1.json @@ -17,5 +17,5 @@ "freeDisk": 120935100007, "freeMemory": 2234092234234, "orientation": "landscape", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" } \ No newline at end of file diff --git a/bugsnag-android-core/src/test/resources/event_redaction.json b/bugsnag-android-core/src/test/resources/event_redaction.json index 15ac42f05c..320549ad51 100644 --- a/bugsnag-android-core/src/test/resources/event_redaction.json +++ b/bugsnag-android-core/src/test/resources/event_redaction.json @@ -35,11 +35,11 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [ { - "timestamp": "1970-01-01T00:00:00Z", + "timestamp": "1970-01-01T00:00:00.000Z", "name": "Whoops", "type": "log", "metaData": { diff --git a/bugsnag-android-core/src/test/resources/event_serialization_0.json b/bugsnag-android-core/src/test/resources/event_serialization_0.json index 91d6009c74..8a6e345dca 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_0.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_0.json @@ -25,7 +25,7 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [], "threads": [] diff --git a/bugsnag-android-core/src/test/resources/event_serialization_1.json b/bugsnag-android-core/src/test/resources/event_serialization_1.json index d3788bcbe4..92daa508d2 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_1.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_1.json @@ -26,7 +26,7 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [], "threads": [] diff --git a/bugsnag-android-core/src/test/resources/event_serialization_2.json b/bugsnag-android-core/src/test/resources/event_serialization_2.json index 9f17700a17..308f21abc3 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_2.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_2.json @@ -25,7 +25,7 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [], "groupingHash": "herpderp", diff --git a/bugsnag-android-core/src/test/resources/event_serialization_3.json b/bugsnag-android-core/src/test/resources/event_serialization_3.json index 9d83e87d76..1163b23339 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_3.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_3.json @@ -25,7 +25,7 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [], "threads": [] diff --git a/bugsnag-android-core/src/test/resources/event_serialization_4.json b/bugsnag-android-core/src/test/resources/event_serialization_4.json index 96cc0187ae..275b880b64 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_4.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_4.json @@ -25,13 +25,13 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [], "threads": [], "session": { "id": "123", - "startedAt": "1970-01-01T00:00:00Z", + "startedAt": "1970-01-01T00:00:00.000Z", "events": { "handled": 0, "unhandled": 0 diff --git a/bugsnag-android-core/src/test/resources/event_serialization_5.json b/bugsnag-android-core/src/test/resources/event_serialization_5.json index c2e9b82170..cbc8d73f3b 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_5.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_5.json @@ -25,7 +25,7 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [], "threads": [ diff --git a/bugsnag-android-core/src/test/resources/event_serialization_6.json b/bugsnag-android-core/src/test/resources/event_serialization_6.json index 42a75129c5..f27c4bcc62 100644 --- a/bugsnag-android-core/src/test/resources/event_serialization_6.json +++ b/bugsnag-android-core/src/test/resources/event_serialization_6.json @@ -44,11 +44,11 @@ "freeDisk": 22234423124, "freeMemory": 92340255592, "orientation": "portrait", - "time": "1970-01-01T00:00:00Z" + "time": "1970-01-01T00:00:00.000Z" }, "breadcrumbs": [ { - "timestamp": "1970-01-01T00:00:00Z", + "timestamp": "1970-01-01T00:00:00.000Z", "name": "helloworld", "type": "manual", "metaData": {} diff --git a/bugsnag-android-core/src/test/resources/json_stream.json b/bugsnag-android-core/src/test/resources/json_stream.json index 702d808d3b..367a7aa4a1 100644 --- a/bugsnag-android-core/src/test/resources/json_stream.json +++ b/bugsnag-android-core/src/test/resources/json_stream.json @@ -5,7 +5,7 @@ "long": 123, "float": 123.45, "streamable": { - "timestamp": "1970-01-01T00:00:00Z", + "timestamp": "1970-01-01T00:00:00.000Z", "name": "whoops", "type": "log", "metaData": {} diff --git a/bugsnag-android-core/src/test/resources/session_serialization_0.json b/bugsnag-android-core/src/test/resources/session_serialization_0.json index 222365da53..d2bf114531 100644 --- a/bugsnag-android-core/src/test/resources/session_serialization_0.json +++ b/bugsnag-android-core/src/test/resources/session_serialization_0.json @@ -23,7 +23,7 @@ "sessions": [ { "id": "123", - "startedAt": "1970-01-01T00:00:00Z", + "startedAt": "1970-01-01T00:00:00.000Z", "user": {} } ] diff --git a/bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/DeviceSerializationTest.kt b/bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/DeviceSerializationTest.kt index d562a0c578..b8695c0205 100644 --- a/bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/DeviceSerializationTest.kt +++ b/bugsnag-plugin-android-ndk/src/androidTest/java/com/bugsnag/android/ndk/DeviceSerializationTest.kt @@ -27,6 +27,9 @@ internal class DeviceSerializationTest { @Test fun testPassesNativeSuite() { val expectedJson = loadJson("device_serialization_$testCase.json") - verifyNativeRun(run(testCase.toInt(), expectedJson)) + // sanitize device time to standard value + val timestampEnd = expectedJson.indexOf("Z\"}}") + val sanitizedJson = expectedJson.replaceRange(timestampEnd - 3, timestampEnd, "000") + verifyNativeRun(run(testCase.toInt(), sanitizedJson)) } } diff --git a/bugsnag-plugin-android-ndk/src/androidTest/resources/device_serialization_0.json b/bugsnag-plugin-android-ndk/src/androidTest/resources/device_serialization_0.json index 9d23906ab4..d2e9a09ace 100644 --- a/bugsnag-plugin-android-ndk/src/androidTest/resources/device_serialization_0.json +++ b/bugsnag-plugin-android-ndk/src/androidTest/resources/device_serialization_0.json @@ -1 +1 @@ -{"device":{"osName":"android","id":"f5gh7","locale":"En","osVersion":"8.1","manufacturer":"Samsung","model":"S7","orientation":"portrait","runtimeVersions":{"androidApiLevel":29,"osBuild":"BullDog 5.2"},"cpuAbi":["x86"],"totalMemory":512340922,"jailbroken":true,"time":"2029-01-01T00:00:00Z"}} \ No newline at end of file +{"device":{"osName":"android","id":"f5gh7","locale":"En","osVersion":"8.1","manufacturer":"Samsung","model":"S7","orientation":"portrait","runtimeVersions":{"androidApiLevel":29,"osBuild":"BullDog 5.2"},"cpuAbi":["x86"],"totalMemory":512340922,"jailbroken":true,"time":"2029-01-01T00:00:00.000Z"}} \ No newline at end of file diff --git a/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c b/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c index a12b986b84..628480aec0 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c +++ b/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c @@ -385,7 +385,7 @@ void bsg_serialize_app_metadata(const bsg_app_info app, JSON_Object *event_obj) json_object_dotset_string(event_obj, "metaData.app.activeScreen", app.active_screen); } -void bsg_serialize_device(const bsg_device_info device, JSON_Object *event_obj) { +void bsg_serialize_device(const bsg_device_info device, JSON_Object *event_obj, struct timeval current_time) { json_object_dotset_string(event_obj, "device.osName", device.os_name); json_object_dotset_string(event_obj, "device.id", device.id); json_object_dotset_string(event_obj, "device.locale", device.locale); @@ -406,9 +406,11 @@ void bsg_serialize_device(const bsg_device_info device, JSON_Object *event_obj) json_object_dotset_number(event_obj, "device.totalMemory", device.total_memory); json_object_dotset_boolean(event_obj, "device.jailbroken", device.jailbroken); - char report_time[sizeof "2018-10-08T12:07:09Z"]; if (device.time > 0) { - strftime(report_time, sizeof report_time, "%FT%TZ", gmtime(&device.time)); + int milliseconds = current_time.tv_usec / 1000; + char report_time[sizeof "2018-10-08T12:07:09.000Z"]; + strftime(report_time, sizeof report_time, "%FT%T", gmtime(&device.time)); + sprintf(report_time, "%s.%03dZ", report_time, milliseconds); json_object_dotset_string(event_obj, "device.time", report_time); } } @@ -563,7 +565,10 @@ char *bsg_serialize_event_to_json_string(bugsnag_event *event) { bsg_serialize_handled_state(event, event_obj); bsg_serialize_app(event->app, event_obj); bsg_serialize_app_metadata(event->app, event_obj); - bsg_serialize_device(event->device, event_obj); + + struct timeval current_time = {}; + gettimeofday(¤t_time, NULL); + bsg_serialize_device(event->device, event_obj, current_time); bsg_serialize_device_metadata(event->device, event_obj); bsg_serialize_custom_metadata(event->metadata, event_obj); bsg_serialize_user(event->user, event_obj); diff --git a/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.h b/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.h index 6b65b2e738..bdf29d06f4 100644 --- a/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.h +++ b/bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.h @@ -21,7 +21,7 @@ void bsg_serialize_context(const bugsnag_event *event, JSON_Object *event_obj); void bsg_serialize_handled_state(const bugsnag_event *event, JSON_Object *event_obj); void bsg_serialize_app(const bsg_app_info app, JSON_Object *event_obj); void bsg_serialize_app_metadata(const bsg_app_info app, JSON_Object *event_obj); -void bsg_serialize_device(const bsg_device_info device, JSON_Object *event_obj); +void bsg_serialize_device(const bsg_device_info device, JSON_Object *event_obj, struct timeval current_time); void bsg_serialize_device_metadata(const bsg_device_info device, JSON_Object *event_obj); void bsg_serialize_custom_metadata(const bugsnag_metadata metadata, JSON_Object *event_obj); void bsg_serialize_user(const bugsnag_user user, JSON_Object *event_obj); diff --git a/bugsnag-plugin-android-ndk/src/test/cpp/main.c b/bugsnag-plugin-android-ndk/src/test/cpp/main.c index dddcc3e737..26974222ea 100644 --- a/bugsnag-plugin-android-ndk/src/test/cpp/main.c +++ b/bugsnag-plugin-android-ndk/src/test/cpp/main.c @@ -102,7 +102,8 @@ TEST test_device_serialization(test_case *test_case) { JSON_Value *event_val = json_value_init_object(); JSON_Object *event = json_value_get_object(event_val); bsg_device_info *device = test_case->data_ptr; - bsg_serialize_device(*device, event); + struct timeval current_time = {}; + bsg_serialize_device(*device, event, current_time); free(device); return validate_serialized_json(test_case, event_val); } diff --git a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/BreadcrumbSerializerTest.java b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/BreadcrumbSerializerTest.java index 3af45b38e0..10d8f99d4e 100644 --- a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/BreadcrumbSerializerTest.java +++ b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/BreadcrumbSerializerTest.java @@ -36,7 +36,7 @@ public void setup() { public void serialize() { Map map = new HashMap<>(); new BreadcrumbSerializer().serialize(map, crumb); - assertEquals("1970-01-01T00:00:00Z", map.get("timestamp")); + assertEquals("1970-01-01T00:00:00.000Z", map.get("timestamp")); assertEquals("Whoops", map.get("message")); assertEquals("state", map.get("type")); assertEquals(metadata, map.get("metadata")); diff --git a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/DeviceSerializerTest.java b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/DeviceSerializerTest.java index 26c88dca69..602a5e4626 100644 --- a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/DeviceSerializerTest.java +++ b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/DeviceSerializerTest.java @@ -70,7 +70,7 @@ public void serialize() { assertEquals(20923423434L, map.get("freeDisk")); assertEquals(23409662345L, map.get("freeMemory")); assertEquals("portrait", map.get("orientation")); - assertEquals("1970-01-01T00:00:00Z", map.get("time")); + assertEquals("1970-01-01T00:00:00.000Z", map.get("time")); Map runtimeVersions = new HashMap<>(); runtimeVersions.put("androidApiLevel", 27);