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

software.amazon.awssdk.metrics.LoggingMetricPublisher Maven / Gradle / Ivy

/*
 * Copyright Amazon.com, Inc. or its affiliates. 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.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.metrics;

import static software.amazon.awssdk.utils.StringUtils.repeat;

import java.util.ArrayList;
import java.util.List;
import org.slf4j.event.Level;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.utils.Logger;
import software.amazon.awssdk.utils.Validate;

/**
 * An implementation of {@link MetricPublisher} that logs all published metrics under the {@code
 * software.amazon.awssdk.metrics.LoggingMetricPublisher} namespace.
 * 

* {@link LoggingMetricPublisher} can be configured with a {@link Level} to control the log level at which metrics are recorded * and a {@link Format} to control the format that metrics are printed in. *

* {@link Format#PLAIN} can be used to print all metrics on a single line. E.g., *

 * Metrics published: MetricCollection(name=ApiCall, metrics=[MetricRecord(metric=MarshallingDuration, value=PT0.000202197S),
 * MetricRecord(metric=RetryCount, value=0), MetricRecord(metric=ApiCallSuccessful, value=true),
 * MetricRecord(metric=OperationName, value=HeadObject), MetricRecord(metric=ApiCallDuration, value=PT0.468369S),
 * MetricRecord(metric=CredentialsFetchDuration, value=PT0.000003191S), MetricRecord(metric=ServiceId, value=S3)],
 * children=[MetricCollection(name=ApiCallAttempt, metrics=[MetricRecord(metric=SigningDuration, value=PT0.000667268S),
 * MetricRecord(metric=ServiceCallDuration, value=PT0.460529977S), MetricRecord(metric=AwsExtendedRequestId,
 * value=jY/Co5Ge6WjRYk78kGOYQ4Z/CqUBr6pAAPZtexgOQR3Iqs3QP0OfZz3fDraQiXtmx7eXCZ4sbO0=), MetricRecord(metric=HttpStatusCode,
 * value=200), MetricRecord(metric=BackoffDelayDuration, value=PT0S), MetricRecord(metric=AwsRequestId, value=6SJ82R65SADHX098)],
 * children=[MetricCollection(name=HttpClient, metrics=[MetricRecord(metric=AvailableConcurrency, value=0),
 * MetricRecord(metric=LeasedConcurrency, value=0), MetricRecord(metric=ConcurrencyAcquireDuration, value=PT0.230757S),
 * MetricRecord(metric=PendingConcurrencyAcquires, value=0), MetricRecord(metric=MaxConcurrency, value=50),
 * MetricRecord(metric=HttpClientName, value=NettyNio)], children=[])])])
 * 
* {@link Format#PRETTY} can be used to print metrics over multiple lines in a readable fashion suitable for debugging. E.g., *
 * [18e5092e] ApiCall
 * [18e5092e] ┌────────────────────────────────────────┐
 * [18e5092e] │ MarshallingDuration=PT0.000227427S     │
 * [18e5092e] │ RetryCount=0                           │
 * [18e5092e] │ ApiCallSuccessful=true                 │
 * [18e5092e] │ OperationName=HeadObject               │
 * [18e5092e] │ ApiCallDuration=PT0.541751S            │
 * [18e5092e] │ CredentialsFetchDuration=PT0.00000306S │
 * [18e5092e] │ ServiceId=S3                           │
 * [18e5092e] └────────────────────────────────────────┘
 * [18e5092e]     ApiCallAttempt
 * [18e5092e]     ┌───────────────────────────────────────────────────────────────────────────────────────────────────┐
 * [18e5092e]     │ SigningDuration=PT0.000974924S                                                                    │
 * [18e5092e]     │ ServiceCallDuration=PT0.531462375S                                                                │
 * [18e5092e]     │ AwsExtendedRequestId=eGfwjV3mSwQZQD4YxHLswYguvhQoGcDTkr2jRvpio37a6QmhWd18C8wagC8LkBzzcnOOKoMuiXw= │
 * [18e5092e]     │ HttpStatusCode=200                                                                                │
 * [18e5092e]     │ BackoffDelayDuration=PT0S                                                                         │
 * [18e5092e]     │ AwsRequestId=ED46TP7NN62DDG4Q                                                                     │
 * [18e5092e]     └───────────────────────────────────────────────────────────────────────────────────────────────────┘
 * [18e5092e]         HttpClient
 * [18e5092e]         ┌────────────────────────────────────────┐
 * [18e5092e]         │ AvailableConcurrency=0                 │
 * [18e5092e]         │ LeasedConcurrency=0                    │
 * [18e5092e]         │ ConcurrencyAcquireDuration=PT0.235851S │
 * [18e5092e]         │ PendingConcurrencyAcquires=0           │
 * [18e5092e]         │ MaxConcurrency=50                      │
 * [18e5092e]         │ HttpClientName=NettyNio                │
 * [18e5092e]         └────────────────────────────────────────┘
 * 
* Note that the output format may be subject to small changes in future versions and should not be relied upon as a strict public * contract. */ @SdkPublicApi public final class LoggingMetricPublisher implements MetricPublisher { public enum Format { PLAIN, PRETTY } private static final Logger LOGGER = Logger.loggerFor(LoggingMetricPublisher.class); private static final Integer PRETTY_INDENT_SIZE = 4; private final Level logLevel; private final Format format; private LoggingMetricPublisher(Level logLevel, Format format) { this.logLevel = Validate.notNull(logLevel, "logLevel"); this.format = Validate.notNull(format, "format"); } /** * Create a {@link LoggingMetricPublisher} with the default configuration of {@link Level#INFO} and {@link Format#PLAIN}. */ public static LoggingMetricPublisher create() { return new LoggingMetricPublisher(Level.INFO, Format.PLAIN); } /** * Create a {@link LoggingMetricPublisher} with a custom {@link Format} and log {@link Level}. * * @param logLevel the SLF4J log level to log metrics with * @param format the format to print the metrics with (see class-level documentation for examples) */ public static LoggingMetricPublisher create(Level logLevel, Format format) { return new LoggingMetricPublisher(logLevel, format); } @Override public void publish(MetricCollection metrics) { if (!LOGGER.isLoggingLevelEnabled(logLevel)) { return; } switch (format) { case PLAIN: LOGGER.log(logLevel, () -> "Metrics published: " + metrics); break; case PRETTY: String guid = Integer.toHexString(metrics.hashCode()); logPretty(guid, metrics, 0); break; default: throw new IllegalStateException("Unsupported format: " + format); } } private void logPretty(String guid, MetricCollection metrics, int indent) { // Pre-determine metric key-value-pairs so that we can calculate the necessary padding List metricValues = new ArrayList<>(); metrics.forEach(m -> { metricValues.add(String.format("%s=%s", m.metric().name(), m.value())); }); int maxLen = getMaxLen(metricValues); // MetricCollection name LOGGER.log(logLevel, () -> String.format("[%s]%s %s", guid, repeat(" ", indent), metrics.name())); // Open box LOGGER.log(logLevel, () -> String.format("[%s]%s ┌%s┐", guid, repeat(" ", indent), repeat("─", maxLen + 2))); // Metric key-value-pairs metricValues.forEach(metric -> LOGGER.log(logLevel, () -> { return String.format("[%s]%s │ %s │", guid, repeat(" ", indent), pad(metric, maxLen)); })); // Close box LOGGER.log(logLevel, () -> String.format("[%s]%s └%s┘", guid, repeat(" ", indent), repeat("─", maxLen + 2))); // Recursively repeat for any children metrics.children().forEach(child -> logPretty(guid, child, indent + PRETTY_INDENT_SIZE)); } private static int getMaxLen(List strings) { int maxLen = 0; for (String str : strings) { maxLen = Math.max(maxLen, str.length()); } return maxLen; } private static String pad(String str, int length) { return str + repeat(" ", length - str.length()); } @Override public void close() { } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy