|
| 1 | +/* |
| 2 | + * Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | + * contributor license agreements. See the NOTICE file distributed with |
| 4 | + * this work for additional information regarding copyright ownership. |
| 5 | + * The ASF licenses this file to You under the Apache License, Version 2.0 |
| 6 | + * (the "License"); you may not use this file except in compliance with |
| 7 | + * the License. You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + * |
| 17 | + */ |
| 18 | + |
| 19 | +package org.apache.skywalking.apm.plugin.kotlin.coroutine; |
| 20 | + |
| 21 | +import kotlin.coroutines.AbstractCoroutineContextElement; |
| 22 | +import kotlin.coroutines.CoroutineContext; |
| 23 | +import kotlinx.coroutines.ThreadContextElement; |
| 24 | +import org.apache.skywalking.apm.agent.core.context.ContextManager; |
| 25 | +import org.apache.skywalking.apm.agent.core.context.ContextSnapshot; |
| 26 | +import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; |
| 27 | +import org.apache.skywalking.apm.agent.core.logging.api.ILog; |
| 28 | +import org.apache.skywalking.apm.agent.core.logging.api.LogManager; |
| 29 | +import org.apache.skywalking.apm.network.trace.component.ComponentsDefine; |
| 30 | +import org.jetbrains.annotations.NotNull; |
| 31 | + |
| 32 | +public class TracingCoroutineContext extends AbstractCoroutineContextElement implements ThreadContextElement<AbstractSpan> { |
| 33 | + private static class Key implements CoroutineContext.Key<TracingCoroutineContext> { |
| 34 | + public static final Key INSTANCE = new Key(); |
| 35 | + |
| 36 | + private Key() { |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + private static final String COROUTINE_OPERATION = "Kotlin/Coroutine"; |
| 41 | + |
| 42 | + private static final ILog LOG = LogManager.getLogger(TracingCoroutineContext.class); |
| 43 | + |
| 44 | + private final ContextSnapshot snapshot; |
| 45 | + |
| 46 | + public TracingCoroutineContext(ContextSnapshot snapshot) { |
| 47 | + super(Key.INSTANCE); |
| 48 | + this.snapshot = snapshot; |
| 49 | + } |
| 50 | + |
| 51 | + @Override |
| 52 | + public void restoreThreadContext(@NotNull CoroutineContext coroutineContext, AbstractSpan span) { |
| 53 | + if (ContextManager.isActive() && span != null) { |
| 54 | + ContextManager.stopSpan(span); |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + @Override |
| 59 | + public AbstractSpan updateThreadContext(@NotNull CoroutineContext coroutineContext) { |
| 60 | + // Coroutine will be executed in a new thread, we need recover our tracing context in this thread. |
| 61 | + |
| 62 | + // Snapshot is null means tracing is disabled in current coroutine. |
| 63 | + if (snapshot != null) { |
| 64 | + |
| 65 | + // Tracing is enabled on the target dispatched thread. |
| 66 | + if (ContextManager.isActive()) { |
| 67 | + |
| 68 | + // If the trace context is from the snapshot, it means that the thread has not been switched, |
| 69 | + // and there is no need to create a cross-thread span. |
| 70 | + // If not, it means that we are scheduled to a dirty thread, we log a warning and give up to |
| 71 | + // create cross-thread span. |
| 72 | + if (!snapshot.isFromCurrent()) { |
| 73 | + LOG.warn("Kotlin coroutine has been dispatched to a dirty thread which with active span: {}.", ContextManager.getGlobalTraceId()); |
| 74 | + } |
| 75 | + return null; |
| 76 | + } |
| 77 | + |
| 78 | + AbstractSpan span = ContextManager.createLocalSpan(COROUTINE_OPERATION); |
| 79 | + span.setComponent(ComponentsDefine.KT_COROUTINE); |
| 80 | + // Recover with snapshot |
| 81 | + ContextManager.continued(snapshot); |
| 82 | + return span; |
| 83 | + } |
| 84 | + |
| 85 | + return null; |
| 86 | + } |
| 87 | +} |
0 commit comments