Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions e2e-cli/src/main/kotlin/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import com.google.gson.reflect.TypeToken
import com.segment.analytics.Analytics
import com.segment.analytics.Callback
import com.segment.analytics.messages.*
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
Expand Down Expand Up @@ -107,14 +111,20 @@ fun sendEvent(analytics: Analytics, event: Map<String, Any>) {
val userId = event["userId"] as? String ?: ""
val anonymousId = event["anonymousId"] as? String
val messageId = event["messageId"] as? String
val timestamp = event["timestamp"] as? String
@Suppress("UNCHECKED_CAST")
val traits = event["traits"] as? Map<String, Any> ?: emptyMap()
@Suppress("UNCHECKED_CAST")
val properties = event["properties"] as? Map<String, Any> ?: emptyMap()
val eventName = event["event"] as? String
val name = event["name"] as? String
val category = event["category"] as? String
val groupId = event["groupId"] as? String
val previousId = event["previousId"] as? String
@Suppress("UNCHECKED_CAST")
val context = event["context"] as? Map<String, Any>
@Suppress("UNCHECKED_CAST")
val integrations = event["integrations"] as? Map<String, Any>

val messageBuilder: MessageBuilder<*, *> = when (type) {
"identify" -> {
Expand Down Expand Up @@ -154,6 +164,37 @@ fun sendEvent(analytics: Analytics, event: Map<String, Any>) {
if (anonymousId != null) {
messageBuilder.anonymousId(anonymousId)
}
if (messageId != null) {
messageBuilder.messageId(messageId)
}
if (timestamp != null) {
messageBuilder.timestamp(parseTimestamp(timestamp))
}
if (context != null) {
messageBuilder.context(context)
}
if (integrations != null) {
for ((key, value) in integrations) {
when (value) {
is Boolean -> messageBuilder.enableIntegration(key, value)
is Map<*, *> -> @Suppress("UNCHECKED_CAST")
messageBuilder.integrationOptions(key, value as Map<String, Any>)
}
}
}

analytics.enqueue(messageBuilder)
}

private fun parseTimestamp(iso: String): Date {
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)
format.timeZone = TimeZone.getTimeZone("UTC")
return try {
format.parse(iso)!!
} catch (_: Exception) {
// Fallback: try without millis
val fallback = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)
fallback.timeZone = TimeZone.getTimeZone("UTC")
fallback.parse(iso)!!
}
Copy link
Copy Markdown

@didiergarcia didiergarcia Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am always suspicious of the jvm and date functions so I gave this function to claude:

This Kotlin timestamp parsing function has a few issues:
Problems:

  1. Uses deprecated SimpleDateFormat - java.time.Instant and java.time.format.DateTimeFormatter are preferred in modern code
  2. Force unwraps with !! - Can throw NPE if parsing fails in both attempts
  3. Silent exception swallowing - The catch block ignores the original exception, making debugging harder
  4. Creates formatters on every call - SimpleDateFormat creation is expensive
    Potential runtime issue:
    If the fallback also fails to parse, you'll get a NullPointerException from the !! operator with no context about the original parsing error.

I think we address at least the issue where we don't show the parse error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New code is much simpler, better?

}