All Downloads are FREE. Search and download functionalities are using the official Maven repository.

assignment.AssignmentTracker.kt Maven / Gradle / Ivy

The newest version!
package com.amplitude.assignment

import com.amplitude.Amplitude
import com.amplitude.AssignmentConfiguration
import com.amplitude.AssignmentEvent
import com.amplitude.AssignmentEventFilter
import com.amplitude.AssignmentEventSend
import com.amplitude.AssignmentEventSendFailure
import com.amplitude.Event
import com.amplitude.Metrics
import com.amplitude.util.deviceId
import com.amplitude.util.groups
import com.amplitude.util.logger
import com.amplitude.util.userId
import org.json.JSONObject

private object FlagType {
    const val RELEASE = "release"
    const val EXPERIMENT = "experiment"
    const val MUTUAL_EXCLUSION_GROUP = "mutual-exclusion-group"
    const val HOLDOUT_GROUP = "holdout-group"
    const val RELEASE_GROUP = "release-group"
}

internal interface AssignmentTracker {
    suspend fun track(assignment: Assignment)
}

internal class AmplitudeAssignmentTracker(
    private val amplitude: Amplitude,
    private val assignmentFilter: AssignmentFilter,
) : AssignmentTracker {
    companion object {
        val log by logger()
    }

    constructor(
        apiKey: String,
        serverUrl: String,
        config: AssignmentConfiguration,
    ) : this (
        amplitude =
            Amplitude.getInstance().apply {
                setServerUrl(serverUrl)
                setEventUploadThreshold(config.eventUploadThreshold)
                setEventUploadPeriodMillis(config.eventUploadPeriodMillis)
                useBatchMode(config.useBatchMode)
                init(apiKey)
            },
        assignmentFilter = InMemoryAssignmentFilter(config.filterCapacity),
    )

    override suspend fun track(assignment: Assignment) {
        try {
            Metrics.track(AssignmentEvent)
            if (assignmentFilter.shouldTrack(assignment)) {
                Metrics.with({ AssignmentEventSend }, { e -> AssignmentEventSendFailure(e) }) {
                    amplitude.logEvent(assignment.toAmplitudeEvent())
                }
            } else {
                Metrics.track(AssignmentEventFilter)
            }
        } catch (e: Exception) {
            log.error("Failed to track assignment event", e)
        }
    }
}

internal fun Assignment.toAmplitudeEvent(): Event {
    val event =
        Event(
            "[Experiment] Assignment",
            this.context.userId(),
            this.context.deviceId(),
        )
    val groups = this.context.groups()
    if (!groups.isNullOrEmpty()) {
        event.groups = JSONObject(groups)
    }
    event.eventProperties =
        JSONObject().apply {
            for ((flagKey, variant) in [email protected]) {
                val version = variant.metadata?.get("flagVersion")
                val segmentName = variant.metadata?.get("segmentName")
                val details = "v$version rule:$segmentName"
                put("$flagKey.variant", variant.key)
                put("$flagKey.details", details)
            }
        }
    event.userProperties =
        JSONObject().apply {
            val set = JSONObject()
            val unset = JSONObject()
            for ((flagKey, variant) in [email protected]) {
                val flagType = variant.metadata?.get("flagType") as? String
                val default = variant.metadata?.get("default") as? Boolean ?: false
                if (flagType == FlagType.MUTUAL_EXCLUSION_GROUP) {
                    // Dont set user properties for mutual exclusion groups.
                    continue
                } else if (default) {
                    unset.put("[Experiment] $flagKey", "-")
                } else {
                    set.put("[Experiment] $flagKey", variant.key)
                }
            }
            put("\$set", set)
            put("\$unset", unset)
        }
    event.insertId = "${this.context.userId()} ${this.context.deviceId()} ${this.canonicalize().hashCode()} ${this.timestamp / DAY_MILLIS}"
    return event
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy