44import io .sentry .protocol .SentryId ;
55import io .sentry .vendor .gson .stream .JsonToken ;
66import java .io .IOException ;
7+ import java .util .Date ;
78import java .util .HashMap ;
89import java .util .Map ;
910import org .jetbrains .annotations .ApiStatus ;
@@ -20,6 +21,8 @@ public final class SentryEnvelopeHeader implements JsonSerializable, JsonUnknown
2021
2122 private final @ Nullable TraceContext traceContext ;
2223
24+ private @ Nullable Date sentAt ;
25+
2326 private @ Nullable Map <String , Object > unknown ;
2427
2528 public SentryEnvelopeHeader (
@@ -56,12 +59,33 @@ public SentryEnvelopeHeader() {
5659 return traceContext ;
5760 }
5861
62+ /**
63+ * Get the timestamp when the event was sent from the SDK as string in RFC 3339 format. Used for
64+ * clock drift correction of the event timestamp. The time zone must be UTC.
65+ */
66+ public @ Nullable Date getSentAt () {
67+ return sentAt ;
68+ }
69+
70+ /**
71+ * Set he timestamp when the event was sent from the SDK as string in RFC 3339 format. Used * for
72+ * clock drift correction of the event timestamp. The time zone must be UTC.
73+ *
74+ * @param sentAt The timestamp should be generated as close as possible to the transmission of the
75+ * event, so that the delay between sending the envelope and receiving it on the server-side
76+ * is minimized.
77+ */
78+ public void setSentAt (@ Nullable Date sentAt ) {
79+ this .sentAt = sentAt ;
80+ }
81+
5982 // JsonSerializable
6083
6184 public static final class JsonKeys {
6285 public static final String EVENT_ID = "event_id" ;
6386 public static final String SDK = "sdk" ;
6487 public static final String TRACE = "trace" ;
88+ public static final String SENT_AT = "sent_at" ;
6589 }
6690
6791 @ Override
@@ -77,6 +101,9 @@ public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger)
77101 if (traceContext != null ) {
78102 writer .name (JsonKeys .TRACE ).value (logger , traceContext );
79103 }
104+ if (sentAt != null ) {
105+ writer .name (JsonKeys .SENT_AT ).value (logger , DateUtils .getTimestamp (sentAt ));
106+ }
80107 if (unknown != null ) {
81108 for (String key : unknown .keySet ()) {
82109 Object value = unknown .get (key );
@@ -96,6 +123,7 @@ public static final class Deserializer implements JsonDeserializer<SentryEnvelop
96123 SentryId eventId = null ;
97124 SdkVersion sdkVersion = null ;
98125 TraceContext traceContext = null ;
126+ Date sentAt = null ;
99127 Map <String , Object > unknown = null ;
100128
101129 while (reader .peek () == JsonToken .NAME ) {
@@ -110,6 +138,9 @@ public static final class Deserializer implements JsonDeserializer<SentryEnvelop
110138 case JsonKeys .TRACE :
111139 traceContext = reader .nextOrNull (logger , new TraceContext .Deserializer ());
112140 break ;
141+ case JsonKeys .SENT_AT :
142+ sentAt = reader .nextDateOrNull (logger );
143+ break ;
113144 default :
114145 if (unknown == null ) {
115146 unknown = new HashMap <>();
@@ -120,6 +151,7 @@ public static final class Deserializer implements JsonDeserializer<SentryEnvelop
120151 }
121152 SentryEnvelopeHeader sentryEnvelopeHeader =
122153 new SentryEnvelopeHeader (eventId , sdkVersion , traceContext );
154+ sentryEnvelopeHeader .setSentAt (sentAt );
123155 sentryEnvelopeHeader .setUnknown (unknown );
124156 reader .endObject ();
125157 return sentryEnvelopeHeader ;
0 commit comments