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

com.vaadin.extension.instrumentation.communication.StreamRequestHandlerInstrumentation Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
/*-
 * Copyright (C) 2022 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 *
 * See  for the full
 * license.
 */
package com.vaadin.extension.instrumentation.communication;

import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;

import com.vaadin.extension.InstrumentationHelper;
import com.vaadin.flow.server.VaadinRequest;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.instrumentation.api.instrumenter.LocalRootSpan;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

import java.time.Instant;

/**
 * Instruments StreamRequestHandler in order to add a span when the handler is
 * called.
 */
public class StreamRequestHandlerInstrumentation
        implements TypeInstrumentation {
    @Override
    public ElementMatcher classLoaderOptimization() {
        return hasClassesNamed(
                "com.vaadin.flow.server.communication.StreamRequestHandler");
    }

    @Override
    public ElementMatcher typeMatcher() {
        return named(
                "com.vaadin.flow.server.communication.StreamRequestHandler");
    }

    @Override
    public void transform(TypeTransformer transformer) {
        transformer.applyAdviceToMethod(
                named("handleRequest").and(takesArgument(1,
                        named("com.vaadin.flow.server.VaadinRequest"))),
                this.getClass().getName() + "$HandleRequestAdvice");
    }

    @SuppressWarnings("unused")
    public static class HandleRequestAdvice {
        @Advice.OnMethodEnter()
        public static void onEnter(
                @Advice.Local("startTimestamp") Instant startTimestamp) {
            startTimestamp = Instant.now();
        }

        @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
        public static void onExit(@Advice.Thrown Throwable throwable,
                @Advice.Return boolean handled,
                @Advice.Argument(1) VaadinRequest request,
                @Advice.Local("startTimestamp") Instant startTimestamp) {
            if (!handled) {
                // Do not add a span if static file is not served from here.
                return;
            }

            final String spanName = "Handle dynamic file";
            Span span = InstrumentationHelper.startSpan(spanName,
                    startTimestamp);

            // Update root span
            String pathInfo = request.getPathInfo();
            String[] pathParts = pathInfo.split("/");
            String filename = pathParts[pathParts.length - 1];
            String rootSpanName = "/dynamic/resource/[ui]/[secret]/" + filename;

            Span localRootSpan = LocalRootSpan.current();
            localRootSpan.updateName(rootSpanName);
            localRootSpan.setAttribute(SemanticAttributes.HTTP_TARGET,
                    request.getPathInfo());
            localRootSpan.setAttribute(SemanticAttributes.HTTP_ROUTE,
                    rootSpanName);

            InstrumentationHelper.endSpan(span, throwable, null);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy