/* * 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.addthis.hydra.data.filter.bundle; import java.util.concurrent.atomic.AtomicLong; import com.addthis.basis.util.JitterClock; import com.addthis.basis.util.LessStrings; import com.addthis.bundle.core.Bundle; import com.addthis.bundle.core.BundlePrinter; import com.google.common.base.Preconditions; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This {@link BundleFilter BundleFilter} <span class="hydra-summary">outputs debugging information</span>. * <p/> * <p>This filter will print out the contents of the first n bundles to the console output, * where n is determined by the parameter {@link #maxBundles maxBundles}.</p> * <p/> * <p>Example:</p> * <pre> * {debug.every: 10} * </pre> * * @user-reference */ public class BundleFilterDebugPrint implements BundleFilter { private static final int MAX_BUNDLE_LIMIT = 1000; private static final Logger log = LoggerFactory.getLogger(BundleFilterDebugPrint.class); /** * A string prefix to pre-append to the debugging information. Default is "". */ private final String prefix; /** * If true then this filter returns false. Default is false (ie. the filter returns true). */ private final boolean fail; /** * Maximum number of bundles to print. Default is 100. */ private final long maxBundles; /** * Optionally specify to print a bundle every N seconds if * parameter is a positive integer. Default is 0. */ private final long every; @JsonCreator public BundleFilterDebugPrint(@JsonProperty("prefix") String prefix, @JsonProperty("fail") boolean fail, @JsonProperty("maxBundles") long maxBundles, @JsonProperty("every") long every) { Preconditions.checkArgument(maxBundles < MAX_BUNDLE_LIMIT, "Max bundles must be < " + MAX_BUNDLE_LIMIT); this.prefix = prefix; this.fail = fail; this.maxBundles = maxBundles; this.every = every; } private final AtomicLong bundleCounter = new AtomicLong(); private final AtomicLong bundleTimer = new AtomicLong(); // Should be used solely for unit testing. private String cacheOutput = null; // Should be used solely for unit testing. private boolean enableCacheOutput = false; BundleFilterDebugPrint enableCacheOutput() { this.enableCacheOutput = true; return this; } String getCacheOutput() { return cacheOutput; } public static String formatBundle(Bundle bundle) { return BundlePrinter.printBundle(bundle); } private boolean testBundleTimer() { if (every <= 0) { return false; } while (true) { long current = JitterClock.globalTime(); long previous = bundleTimer.get(); if (current - previous > (every * 1000)) { if (bundleTimer.compareAndSet(previous, current)) { return true; } } else { return false; } } } @Override public boolean filter(Bundle bundle) { boolean print = (bundleCounter.getAndIncrement() < maxBundles) || testBundleTimer(); if (print) { String bundleString = formatBundle(bundle); if (LessStrings.isEmpty(prefix)) { log.info(bundleString); } else { log.info(prefix + " : " + bundleString); } if (enableCacheOutput) { cacheOutput = bundleString; } } return !fail; } }