44package software.aws.toolkits.jetbrains.services.telemetry.otel
55
66import com.intellij.openapi.application.ApplicationInfo
7+ import com.intellij.openapi.application.ApplicationManager
78import com.intellij.platform.diagnostic.telemetry.helpers.useWithoutActiveScope
89import io.opentelemetry.api.common.AttributeKey
910import io.opentelemetry.api.common.Attributes
@@ -14,12 +15,14 @@ import io.opentelemetry.api.trace.SpanKind
1415import io.opentelemetry.context.Context
1516import io.opentelemetry.context.ContextKey
1617import io.opentelemetry.context.Scope
18+ import io.opentelemetry.sdk.trace.ReadWriteSpan
1719import kotlinx.coroutines.CoroutineScope
1820import software.amazon.awssdk.services.toolkittelemetry.model.AWSProduct
21+ import software.aws.toolkits.core.utils.error
1922import software.aws.toolkits.core.utils.getLogger
2023import software.aws.toolkits.core.utils.warn
24+ import software.aws.toolkits.jetbrains.isDeveloperMode
2125import software.aws.toolkits.jetbrains.services.telemetry.PluginResolver
22- // import software.aws.toolkits.telemetry.BaseSpan
2326import java.time.Instant
2427import java.util.concurrent.TimeUnit
2528import kotlin.coroutines.CoroutineContext
@@ -30,13 +33,6 @@ import com.intellij.platform.diagnostic.telemetry.helpers.useWithScope as ijUseW
3033val AWS_PRODUCT_CONTEXT_KEY = ContextKey .named<AWSProduct >(" pluginDescriptor" )
3134internal val PLUGIN_ATTRIBUTE_KEY = AttributeKey .stringKey(" plugin" )
3235
33- // class DefaultSpan(context: Context?, delegate: Span) : BaseSpan<DefaultSpan>(context, delegate) {
34- // override val metricName = "?????????"
35- // }
36- // class DefaultSpanBuilder(delegate: SpanBuilder) : AbstractSpanBuilder<DefaultSpanBuilder, DefaultSpan>(delegate) {
37- // override fun doStartSpan() = DefaultSpan(parent, delegate.startSpan())
38- // }
39-
4036abstract class AbstractSpanBuilder <
4137 BuilderType : AbstractSpanBuilder <BuilderType , SpanType >,
4238 SpanType : AbstractBaseSpan <SpanType >,
@@ -48,7 +44,7 @@ abstract class AbstractSpanBuilder<
4844 *
4945 * @inheritdoc
5046 */
51- inline fun <T > use (operation : (Span ) -> T ): T =
47+ inline fun <T > use (operation : (SpanType ) -> T ): T =
5248 // FIX_WHEN_MIN_IS_241: not worth fixing for 233
5349 if (ApplicationInfo .getInstance().build.baselineVersion == 233 ) {
5450 startSpan().useWithoutActiveScope { span ->
@@ -185,21 +181,50 @@ abstract class AbstractSpanBuilder<
185181 }
186182}
187183
188- abstract class AbstractBaseSpan <SpanType : AbstractBaseSpan <SpanType >>(internal val context : Context ? , private val delegate : Span ) : Span by delegate {
189- protected abstract val metricName: String
190-
184+ abstract class AbstractBaseSpan <SpanType : AbstractBaseSpan <SpanType >>(internal val context : Context ? , private val delegate : ReadWriteSpan ) : Span by delegate {
185+ protected open val requiredFields: Collection <String > = emptySet()
191186 /* *
192187 * Same as [com.intellij.platform.diagnostic.telemetry.helpers.use] except downcasts to specific subclass of [BaseSpan]
193188 *
194189 * @inheritdoc
195190 */
196- inline fun <T > use (operation : (Span ) -> T ): T =
191+ inline fun <T > use (operation : (SpanType ) -> T ): T =
197192 ijUse { span ->
198193 operation(span as SpanType )
199194 }
200195
201- fun metadata (key : String , value : String ) = setAttribute(key, value) as SpanType
196+ fun metadata (key : String , value : String? ): SpanType {
197+ delegate.setAttribute(key, value)
198+ return this as SpanType
199+ }
200+
201+ override fun end () {
202+ validateRequiredAttributes()
203+ delegate.end()
204+ }
205+
206+ override fun end (timestamp : Long , unit : TimeUnit ) {
207+ validateRequiredAttributes()
208+ delegate.end()
209+ }
210+
211+ private fun validateRequiredAttributes () {
212+ val missingFields = requiredFields.filter { delegate.getAttribute(AttributeKey .stringKey(it)) == null }
213+ val message = { " ${delegate.name} is missing required fields: ${missingFields.joinToString(" , " )} " }
214+
215+ if (missingFields.isNotEmpty()) {
216+ when {
217+ ApplicationManager .getApplication().isUnitTestMode -> error(message())
218+ isDeveloperMode() -> LOG .error(block = message)
219+ else -> LOG .error(block = message)
220+ }
221+ }
222+ }
202223
203224 override fun makeCurrent (): Scope =
204225 context?.with (this )?.makeCurrent() ? : super .makeCurrent()
226+
227+ private companion object {
228+ val LOG = getLogger<AbstractBaseSpan <* >>()
229+ }
205230}
0 commit comments