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

com.arpnetworking.play.metrics.MetricsActionWrapper Maven / Gradle / Ivy

There is a newer version: 0.9.2
Show newest version
/**
 * Copyright 2014 Groupon.com
 *
 * 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 com.arpnetworking.play.metrics;

import com.arpnetworking.metrics.Metrics;
import com.arpnetworking.metrics.MetricsFactory;
import com.arpnetworking.metrics.Timer;
import com.arpnetworking.steno.Logger;
import com.arpnetworking.steno.LoggerFactory;
import com.google.common.base.Strings;
import play.libs.F;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;

/**
 * Simple action wrapper that wraps each call in a metrics timer.
 *
 * TODO(vkoskela): Add to shared library with Play dependency (tsd-core?) [MAI-?]
 *
 * @author Ville Koskela (vkoskela at groupon dot com)
 */
public final class MetricsActionWrapper extends Action.Simple {

    /**
     * Public constructor.
     *
     * @param metricsFactory Instance of MetricsFactory.
     * @param action The Action to wrap.
     */
    public MetricsActionWrapper(final MetricsFactory metricsFactory, final Action action) {
        _metricsFactory = metricsFactory;
        this.delegate = action;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    // CHECKSTYLE.OFF: IllegalThrow
    public F.Promise call(final Http.Context context) throws Throwable {
        // CHECKSTYLE.ON: IllegalThrow

        final Metrics metrics = getMetrics(context);
        final Timer timer = metrics.createTimer(createTimerName(context));
        return delegate.call(context).map(r -> { timer.stop(); metrics.close(); return r; });
        // TODO(vkoskela): Add success/failure counter by mapping on return code. [MAI-279]
    }

    /**
     * Create the name of the timer from a Http.Context.
     *
     * @param context Context of the HTTP request/response.
     * @return Name of the timer for the request/response.
     */
    protected String createTimerName(final Http.Context context) {
        // TODO(vkoskela): Use routes information to replace variable path parts with variable names. [MAI-280]
        final Http.Request r = context.request();
        final StringBuilder metricNameBuilder = new StringBuilder("rest_service/");
        metricNameBuilder.append(r.method());

        if (!Strings.isNullOrEmpty(r.path())) {
            if (!r.path().startsWith("/")) {
                metricNameBuilder.append("/");
            }
            metricNameBuilder.append(r.path());
        }

        return metricNameBuilder.toString();
    }

    private Metrics getMetrics(final Http.Context context) {
        Metrics metrics = (Metrics) context.args.get(METRICS_KEY);
        if (metrics == null) {
            metrics = _metricsFactory.create();
            context.args.put(METRICS_KEY, metrics);
        } else {
            LOGGER.warn()
                    .setMessage("Found metrics in request context; possible issue")
                    .addData("metrics", metrics)
                    .log();
        }
        return metrics;
    }

    private final MetricsFactory _metricsFactory;

    private static final String METRICS_KEY = "metrics";
    private static final Logger LOGGER = LoggerFactory.getLogger(MetricsActionWrapper.class);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy