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

com.palantir.conjure.java.serialization.ParserInstrumentation Maven / Gradle / Ivy

There is a newer version: 8.16.0
Show newest version
/*
 * (c) Copyright 2023 Palantir Technologies Inc. All rights reserved.
 *
 * 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.palantir.conjure.java.serialization;

import com.codahale.metrics.Histogram;
import com.google.common.util.concurrent.RateLimiter;
import com.palantir.logsafe.SafeArg;
import com.palantir.logsafe.exceptions.SafeRuntimeException;
import com.palantir.logsafe.logger.SafeLogger;
import com.palantir.logsafe.logger.SafeLoggerFactory;
import com.palantir.tritium.metrics.registry.SharedTaggedMetricRegistries;

/** Internal utility to record instrumentation from JSON parsers. */
final class ParserInstrumentation {
    // Log at most once per second
    private static final RateLimiter LOGGING_RATE_LIMITER = RateLimiter.create(1);
    private static final SafeLogger log = SafeLoggerFactory.get(ParserInstrumentation.class);

    private final Throwable creationStackTrace;
    private final Histogram parsedStringLength;

    // Using the shared metric registry singleton to avoid API churn in methods that use this instrumentation.
    @SuppressWarnings("deprecation")
    ParserInstrumentation(String format) {
        creationStackTrace = new SafeRuntimeException("Stream factory created here");
        parsedStringLength = JsonParserMetrics.of(SharedTaggedMetricRegistries.getSingleton())
                .stringLength(format);
    }

    /** Returns the input, recording length of the value. */
    String recordStringLength(String value) {
        if (value != null) {
            int length = value.length();
            // Avoid updating a histogram in the common case (small values) because this path will be exceedingly
            // hot. Furthermore, we use sampling reservoirs, so the higher the rate at which we report values, the
            // more likely it becomes that our largest inputs will not be sampled.
            if (length > 1024 * 512) {
                recordNontrivialStringLength(length);
            }
        }
        return value;
    }

    private void recordNontrivialStringLength(int length) {
        parsedStringLength.update(length);
        if (length > 4_000_000 && LOGGING_RATE_LIMITER.tryAcquire()) {
            log.warn(
                    "Detected an unusually large JSON string value",
                    SafeArg.of("length", length),
                    new SafeRuntimeException("Parsed here", creationStackTrace));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy