com.swirlds.state.merkle.logging.StateLogger Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swirlds-state-api Show documentation
Show all versions of swirlds-state-api Show documentation
Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.
/*
* Copyright (C) 2024 Hedera Hashgraph, LLC
*
* 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.swirlds.state.merkle.logging;
import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.FileID;
import com.hedera.hapi.node.base.ScheduleID;
import com.hedera.hapi.node.base.TokenID;
import com.hedera.hapi.node.base.TopicID;
import com.swirlds.fcqueue.FCQueue;
import com.swirlds.state.merkle.disk.OnDiskKey;
import com.swirlds.state.merkle.disk.OnDiskValue;
import com.swirlds.state.merkle.memory.InMemoryKey;
import com.swirlds.state.merkle.memory.InMemoryValue;
import com.swirlds.state.merkle.singleton.ValueLeaf;
import com.swirlds.virtualmap.VirtualMap;
import com.swirlds.virtualmap.internal.merkle.VirtualLeafNode;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* This utility class provides convenient methods for logging state operations for different types of state types.
*/
public class StateLogger {
/** The logger we are using for the State log */
private static final Logger logger = LogManager.getLogger(StateLogger.class);
/**
* The name of the thread that handles transactions. For the sake of the app, to allow logging.
*/
private static final String TRANSACTION_HANDLING_THREAD_NAME = "";
/**
* Log the read of a singleton.
*
* @param label The label of the singleton
* @param value The value of the singleton
* @param The type of the singleton
*/
public static void logSingletonRead(@NonNull final String label, @Nullable final ValueLeaf value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(" READ singleton {} value {}", label, value == null ? "null" : value.getValue());
}
}
/**
* Log when the value of a singleton is written.
*
* @param label The label of the singleton
* @param value The value of the singleton
*/
public static void logSingletonWrite(@NonNull final String label, @Nullable final Object value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(" WRITTEN singleton {} value {}", label, value == null ? "null" : value.toString());
}
}
/**
* Log when a value is added to a queue.
*
* @param label The label of the queue
* @param value The value added to the queue
*/
public static void logQueueAdd(@NonNull final String label, @Nullable final Object value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(" ADD to queue {} value {}", label, value == null ? "null" : value.toString());
}
}
/**
* Log when a value is removed from a queue.
*
* @param label The label of the queue
* @param value The value removed from the queue
*/
public static void logQueueRemove(@NonNull final String label, @Nullable final Object value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(" REMOVE from queue {} value {}", label, value == null ? "null" : value.toString());
}
}
/**
* Log when queue value is peeked.
*
* @param label The label of the queue
* @param value The value peeked from the queue
*/
public static void logQueuePeek(@NonNull final String label, @Nullable final Object value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(" PEEK on queue {} value {}", label, value == null ? "null" : value.toString());
}
}
/**
* Log the iteration over a queue.
*
* @param label The label of the queue
* @param queue The queue that was iterated
* @param The type of the queue values
*/
public static void logQueueIterate(@NonNull final String label, @NonNull final FCQueue> queue) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
if (queue.isEmpty()) {
logger.debug(" ITERATE queue {} size 0 values:EMPTY", label);
} else {
logger.debug(
" ITERATE queue {} size {} values:\n{}",
label,
queue.size(),
queue.stream()
.map(leaf -> leaf == null ? "null" : leaf.toString())
.collect(Collectors.joining(",\n")));
}
}
}
/**
* Log the put of an entry in to a map.
*
* @param label The label of the map
* @param key The key added to the map
* @param value The value added to the map
* @param The type of the key
* @param The type of the value
*/
public static void logMapPut(@NonNull final String label, @NonNull final K key, @Nullable final V value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(
" PUT into map {} key {} value {}",
label,
formatKey(key),
value == null ? "null" : value.toString());
}
}
/**
* Log the removal of an entry from a map.
*
* @param label The label of the map
* @param key The key removed to the map
* @param value The value removed to the map
* @param The type of the key
* @param The type of the value
*/
public static void logMapRemove(
@NonNull final String label, @NonNull final K key, @Nullable final InMemoryValue value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(
" REMOVE from map {} key {} removed value {}",
label,
formatKey(key),
value == null ? "null" : value.toString());
}
}
/**
* Log the removal of an entry from a map.
*
* @param label The label of the map
* @param key The key removed to the map
* @param value The value removed to the map
* @param The type of the key
* @param The type of the value
*/
public static void logMapRemove(
@NonNull final String label, @NonNull final K key, @Nullable final OnDiskValue value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(
" REMOVE from map {} key {} removed value {}",
label,
formatKey(key),
value == null ? "null" : value.toString());
}
}
/**
* Log the fetching of the size of a map.
*
* @param label The label of the map
* @param size The size of the map
*/
public static void logMapGetSize(@NonNull final String label, final long size) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(" GET_SIZE on map {} size {}", label, size);
}
}
/**
* Log the get of an entry from a map.
*
* @param label The label of the map
* @param key The key fetched to the map
* @param value The value fetched to the map
* @param The type of the key
* @param The type of the value
*/
public static void logMapGet(@NonNull final String label, @NonNull final K key, @Nullable final V value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(
" GET on map {} key {} value {}",
label,
formatKey(key),
value == null ? "null" : value.toString());
}
}
/**
* Log the get of an entry from a map for modification.
*
* @param label The label of the map
* @param key The key fetched to the map
* @param value The value fetched to the map
* @param The type of the key
* @param The type of the value
*/
public static void logMapGetForModify(
@NonNull final String label, @NonNull final K key, @Nullable final V value) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
logger.debug(
" GET_FOR_MODIFY on map {} key {} value {}",
label,
formatKey(key),
value == null ? "null" : value.toString());
}
}
/**
* Log the iteration of keys of a map.
*
* @param label The label of the map
* @param keySet The set of keys of the map
* @param The type of the key
*/
public static void logMapIterate(@NonNull final String label, @NonNull final Set> keySet) {
if (logger.isDebugEnabled() && Thread.currentThread().getName().equals(TRANSACTION_HANDLING_THREAD_NAME)) {
final long size = keySet.size();
if (size == 0) {
logger.debug(" ITERATE map {} size 0 keys:EMPTY", label);
} else {
logger.debug(
" ITERATE map {} size {} keys:\n{}",
label,
size,
keySet.stream()
.map(InMemoryKey::key)
.map(StateLogger::formatKey)
.collect(Collectors.joining(",\n")));
}
}
}
/**
* Log the iteration of values of a map.
*
* @param label The label of the map
* @param virtualMap The map that was iterated
* @param The type of the key
* @param The type of the value
*/
public static void logMapIterate(
@NonNull final String label, @NonNull final VirtualMap, OnDiskValue> virtualMap) {
if (logger.isDebugEnabled()) {
final var spliterator = Spliterators.spliterator(
virtualMap.treeIterator(), virtualMap.size(), Spliterator.SIZED & Spliterator.ORDERED);
final long size = virtualMap.size();
if (size == 0) {
logger.debug(" ITERATE map {} size 0 keys:EMPTY", label);
} else {
logger.debug(
" ITERATE map {} size {} keys:\n{}",
label,
size,
StreamSupport.stream(spliterator, false)
.map(merkleNode -> {
if (merkleNode instanceof VirtualLeafNode, ?> leaf) {
final var k = leaf.getKey();
if (k instanceof OnDiskKey> onDiskKey) {
return onDiskKey.getKey().toString();
}
}
return "Unknown_Type";
})
.collect(Collectors.joining(",\n")));
}
}
}
/**
* Format entity id keys in form 0.0.123 rather than default toString() long form.
*
* @param key The key to format
* @return The formatted key
* @param The type of the key
*/
public static String formatKey(@Nullable final K key) {
if (key == null) {
return "null";
} else if (key instanceof AccountID accountID) {
return accountID.shardNum() + "." + accountID.realmNum() + '.' + accountID.accountNum();
} else if (key instanceof FileID fileID) {
return fileID.shardNum() + "." + fileID.realmNum() + '.' + fileID.fileNum();
} else if (key instanceof TokenID tokenID) {
return tokenID.shardNum() + "." + tokenID.realmNum() + '.' + tokenID.tokenNum();
} else if (key instanceof TopicID topicID) {
return topicID.shardNum() + "." + topicID.realmNum() + '.' + topicID.topicNum();
} else if (key instanceof ScheduleID scheduleID) {
return scheduleID.shardNum() + "." + scheduleID.realmNum() + '.' + scheduleID.scheduleNum();
}
return key.toString();
}
}