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

org.finos.legend.server.shared.bundles.OpenTracingBundle Maven / Gradle / Ivy

The newest version!
// Copyright 2020 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.finos.legend.server.shared.bundles;

import com.google.common.collect.ImmutableList;
import io.dropwizard.Bundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.opentracing.Span;
import io.opentracing.contrib.jaxrs2.internal.CastUtils;
import io.opentracing.contrib.jaxrs2.internal.SpanWrapper;
import org.finos.legend.opentracing.jaxrs2.InterceptorSpanDecorator;
import org.finos.legend.opentracing.jaxrs2.ServerTracingInterceptor;
import io.opentracing.log.Fields;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.Principal;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Priorities;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.ext.InterceptorContext;
import javax.ws.rs.ext.ReaderInterceptorContext;
import javax.ws.rs.ext.WriterInterceptorContext;

import org.finos.legend.opentracing.OpenTracingFilter;
import org.finos.legend.opentracing.ServerSpanDecorator;
import org.finos.legend.opentracing.StandardSpanDecorator;

import static io.opentracing.contrib.jaxrs2.internal.SpanWrapper.PROPERTY_NAME;

@SuppressWarnings("unused")
public class OpenTracingBundle implements Bundle
{
  private final List serverSpanDecorators;
  private final List interceptorSpanDecorators;
  private final List skipUrls;

  public OpenTracingBundle()
  {
    this(ImmutableList.of(), ImmutableList.of());
  }

  /**
   * Create OpenTracingBundle.
   *
   * @param decorators Additional decorators to add
   * @param skipUrls   URLs to skip tracing on
   */
  @SuppressWarnings("WeakerAccess")
  public OpenTracingBundle(Iterable decorators, List skipUrls)
  {
    this(decorators, ImmutableList.of(), skipUrls);
  }

  /**
   * Create OpenTracingBundle.
   *
   * @param serverSpanDecorators Additional server span decorators to add, executed around each request/response
   * @param interceptorSpanDecorators Additional interceptor span decorators to add, executed around each request read and response write
   * @param skipUrls   URLs to skip tracing on
   */
  @SuppressWarnings("WeakerAccess")
  public OpenTracingBundle(Iterable serverSpanDecorators, Iterable interceptorSpanDecorators, List skipUrls)
  {
    this.serverSpanDecorators =
            ImmutableList.builder()
                    .addAll(serverSpanDecorators)
                    .add(new StandardSpanDecorator())
                    .add(new UserNameDecorator())
                    .build();

    this.interceptorSpanDecorators =
            ImmutableList.builder()
                    .addAll(interceptorSpanDecorators)
                    .add(InterceptorSpanDecorator.STANDARD_TAGS)
                    .build();

    this.skipUrls = skipUrls;
  }

  @Override
  public void initialize(Bootstrap bootstrap)
  {
  }

  @Override
  public void run(Environment environment)
  {
    if (GlobalTracer.isRegistered())
    {
      final FilterRegistration.Dynamic openTracing =
          environment
              .servlets()
              .addFilter(
                  "OpenTracing",
                  new OpenTracingFilter(GlobalTracer.get(), this.serverSpanDecorators, this.skipUrls));
      openTracing.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
      environment
          .jersey()
          .register(
              (DynamicFeature) (resourceInfo, context) ->
                  context.register(
                      new ServerTracingInterceptor(
                          GlobalTracer.get(),
                          this.interceptorSpanDecorators),
                      Priorities.ENTITY_CODER));
    }
  }

  public static class LogErrorsInterceptorSpanDecorator implements InterceptorSpanDecorator
  {
    @Override
    public void decorateRead(InterceptorContext context, Span span)
    {

    }

    @Override
    public void decorateWrite(InterceptorContext context, Span span)
    {

    }

    @Override
    public void decorateReadException(Exception e, ReaderInterceptorContext context, Span span)
    {
      this.logException(span, e);
      this.errorRootSpan("deserialize", context);
    }

    @Override
    public void decorateWriteException(Exception e, WriterInterceptorContext context, Span span)
    {
      this.logException(span, e);
      this.errorRootSpan("serialize", context);
    }

    private void logException(Span span, Exception e)
    {
      Map errorLogs = new HashMap<>(2);
      errorLogs.put(Fields.EVENT, Tags.ERROR.getKey());
      errorLogs.put(Fields.ERROR_OBJECT, e);
      span.log(errorLogs);
    }

    private void errorRootSpan(String reason, InterceptorContext context)
    {
      SpanWrapper spanWrapper = CastUtils.cast(context.getProperty(PROPERTY_NAME), SpanWrapper.class);
      if (spanWrapper != null && !spanWrapper.isFinished())
      {
        Span rootSpan = spanWrapper.get();
        Tags.ERROR.set(rootSpan, true);
        Map errorLogs = new HashMap<>(2);
        errorLogs.put(Fields.EVENT, Tags.ERROR.getKey());
        errorLogs.put(Fields.MESSAGE, "Error on " + reason);
        rootSpan.log(errorLogs);
      }
    }
  }

  private static class UserNameDecorator implements ServerSpanDecorator
  {

    @Override
    public void decorateRequest(HttpServletRequest request, Span span)
    {
      Principal principal = request.getUserPrincipal();

      if (principal != null)
      {
        String user = principal.getName();
        span.setTag("user", user);
      }

      try
      {
        span.setTag("serverHost", InetAddress.getLocalHost().getCanonicalHostName());
      } catch (UnknownHostException e)
      {
        // Ignore
      }
    }

    @Override
    public void decorateResponse(HttpServletResponse response, Span span)
    {
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy