mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[epilogue] Rename DataLogger to EpilogueBackend for clarity (#7453)
Update documentation and internal names correspondingly
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
|
||||
package edu.wpi.first.epilogue;
|
||||
|
||||
import edu.wpi.first.epilogue.logging.DataLogger;
|
||||
import edu.wpi.first.epilogue.logging.NTDataLogger;
|
||||
import edu.wpi.first.epilogue.logging.EpilogueBackend;
|
||||
import edu.wpi.first.epilogue.logging.NTEpilogueBackend;
|
||||
import edu.wpi.first.epilogue.logging.errors.ErrorHandler;
|
||||
import edu.wpi.first.epilogue.logging.errors.ErrorPrinter;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
@@ -18,11 +18,11 @@ import edu.wpi.first.units.measure.Time;
|
||||
@SuppressWarnings("checkstyle:MemberName")
|
||||
public class EpilogueConfiguration {
|
||||
/**
|
||||
* The data logger implementation for Epilogue to use. By default, this will log data directly to
|
||||
* The backend implementation for Epilogue to use. By default, this will log data directly to
|
||||
* NetworkTables. NetworkTable data can be mirrored to a log file on disk by calling {@code
|
||||
* DataLogManager.start()} in your {@code robotInit} method.
|
||||
*/
|
||||
public DataLogger dataLogger = new NTDataLogger(NetworkTableInstance.getDefault());
|
||||
public EpilogueBackend backend = new NTEpilogueBackend(NetworkTableInstance.getDefault());
|
||||
|
||||
/**
|
||||
* The period Epilogue will log at. By default this is the period that the robot runs at. This is
|
||||
|
||||
@@ -42,26 +42,26 @@ public abstract class ClassSpecificLogger<T> {
|
||||
/**
|
||||
* Updates an object's fields in a data log.
|
||||
*
|
||||
* @param dataLogger the logger to update
|
||||
* @param backend the backend to update
|
||||
* @param object the object to update in the log
|
||||
*/
|
||||
protected abstract void update(DataLogger dataLogger, T object);
|
||||
protected abstract void update(EpilogueBackend backend, T object);
|
||||
|
||||
/**
|
||||
* Attempts to update the data log. Will do nothing if the logger is {@link #disable() disabled}.
|
||||
*
|
||||
* @param dataLogger the logger to log data to
|
||||
* @param backend the backend to log data to
|
||||
* @param object the data object to log
|
||||
* @param errorHandler the handler to use if logging raised an exception
|
||||
*/
|
||||
@SuppressWarnings("PMD.AvoidCatchingGenericException")
|
||||
public final void tryUpdate(DataLogger dataLogger, T object, ErrorHandler errorHandler) {
|
||||
public final void tryUpdate(EpilogueBackend backend, T object, ErrorHandler errorHandler) {
|
||||
if (m_disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
update(dataLogger, object);
|
||||
update(backend, object);
|
||||
} catch (Exception e) {
|
||||
errorHandler.handle(e, this);
|
||||
}
|
||||
@@ -98,10 +98,10 @@ public abstract class ClassSpecificLogger<T> {
|
||||
/**
|
||||
* Logs a sendable type.
|
||||
*
|
||||
* @param dataLogger the logger to log data into
|
||||
* @param backend the backend to log data into
|
||||
* @param sendable the sendable object to log
|
||||
*/
|
||||
protected void logSendable(DataLogger dataLogger, Sendable sendable) {
|
||||
protected void logSendable(EpilogueBackend backend, Sendable sendable) {
|
||||
if (sendable == null) {
|
||||
return;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public abstract class ClassSpecificLogger<T> {
|
||||
m_sendables.computeIfAbsent(
|
||||
sendable,
|
||||
s -> {
|
||||
var b = new LogBackedSendableBuilder(dataLogger);
|
||||
var b = new LogBackedSendableBuilder(backend);
|
||||
s.initSendable(b);
|
||||
return b;
|
||||
});
|
||||
|
||||
@@ -9,40 +9,40 @@ import edu.wpi.first.units.Unit;
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import java.util.Collection;
|
||||
|
||||
/** A data logger is a generic interface for logging discrete data points. */
|
||||
public interface DataLogger {
|
||||
/** A backend is a generic interface for Epilogue to log discrete data points. */
|
||||
public interface EpilogueBackend {
|
||||
/**
|
||||
* Creates a data logger that logs to multiple backends at once. Data reads will still only occur
|
||||
* once; data is passed to all composed loggers at once.
|
||||
* Creates a backend that logs to multiple backends at once. Data reads will still only occur
|
||||
* once; data is passed to all composed backends at once.
|
||||
*
|
||||
* @param loggers the loggers to compose together
|
||||
* @return the multi logger
|
||||
* @param backends the backends to compose together
|
||||
* @return the multi backend
|
||||
*/
|
||||
static DataLogger multi(DataLogger... loggers) {
|
||||
return new MultiLogger(loggers);
|
||||
static EpilogueBackend multi(EpilogueBackend... backends) {
|
||||
return new MultiBackend(backends);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a lazy version of this logger. A lazy logger will only log data to a field when its
|
||||
* Creates a lazy version of this backend. A lazy backend will only log data to a field when its
|
||||
* value changes, which can help keep file size and bandwidth usage in check. However, there is an
|
||||
* additional CPU and memory overhead associated with tracking the current value of every logged
|
||||
* entry. The most surefire way to reduce CPU and memory usage associated with logging is to log
|
||||
* fewer things - which can be done by opting out of logging unnecessary data or increasing the
|
||||
* minimum logged importance level in the Epilogue configuration.
|
||||
*
|
||||
* @return the lazy logger
|
||||
* @return the lazy backend
|
||||
*/
|
||||
default DataLogger lazy() {
|
||||
return new LazyLogger(this);
|
||||
default EpilogueBackend lazy() {
|
||||
return new LazyBackend(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a logger that can be used to log nested data underneath a specific path.
|
||||
* Gets a backend that can be used to log nested data underneath a specific path.
|
||||
*
|
||||
* @param path the path to use for logging nested data under
|
||||
* @return the sub logger
|
||||
* @return the nested backend
|
||||
*/
|
||||
DataLogger getSubLogger(String path);
|
||||
EpilogueBackend getNested(String path);
|
||||
|
||||
/**
|
||||
* Logs a 32-bit integer data point.
|
||||
@@ -26,24 +26,24 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/** A data logger implementation that saves information to a WPILib {@link DataLog} file on disk. */
|
||||
public class FileLogger implements DataLogger {
|
||||
/** A backend implementation that saves information to a WPILib {@link DataLog} file on disk. */
|
||||
public class FileBackend implements EpilogueBackend {
|
||||
private final DataLog m_dataLog;
|
||||
private final Map<String, DataLogEntry> m_entries = new HashMap<>();
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_subLoggers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new file logger.
|
||||
* Creates a new file-based backend.
|
||||
*
|
||||
* @param dataLog the data log to save data to
|
||||
*/
|
||||
public FileLogger(DataLog dataLog) {
|
||||
this.m_dataLog = requireNonNullParam(dataLog, "dataLog", "FileLogger");
|
||||
public FileBackend(DataLog dataLog) {
|
||||
this.m_dataLog = requireNonNullParam(dataLog, "dataLog", "FileBackend");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -11,36 +11,36 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A data logger implementation that only logs data when it changes. Useful for keeping bandwidth
|
||||
* and file sizes down. However, because it still needs to check that data has changed, it cannot
|
||||
* avoid expensive sensor reads.
|
||||
* A backend implementation that only logs data when it changes. Useful for keeping bandwidth and
|
||||
* file sizes down. However, because it still needs to check that data has changed, it cannot avoid
|
||||
* expensive sensor reads.
|
||||
*/
|
||||
public class LazyLogger implements DataLogger {
|
||||
private final DataLogger m_logger;
|
||||
public class LazyBackend implements EpilogueBackend {
|
||||
private final EpilogueBackend m_backend;
|
||||
|
||||
// Keep a record of the most recent value written to each entry
|
||||
// Note that this may duplicate a lot of data, and will box primitives.
|
||||
private final Map<String, Object> m_previousValues = new HashMap<>();
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_subLoggers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new lazy logger wrapper around another logger.
|
||||
* Creates a new lazy backend wrapper around another backend.
|
||||
*
|
||||
* @param logger the logger to delegate to
|
||||
* @param backend the backend to delegate to
|
||||
*/
|
||||
public LazyLogger(DataLogger logger) {
|
||||
this.m_logger = logger;
|
||||
public LazyBackend(EpilogueBackend backend) {
|
||||
this.m_backend = backend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger lazy() {
|
||||
public EpilogueBackend lazy() {
|
||||
// Already lazy, don't need to wrap it again
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,7 +53,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,7 +66,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +79,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,7 +92,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,7 +105,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,7 +118,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,7 +131,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,7 +144,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,7 +157,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,7 +170,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,7 +183,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -196,7 +196,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,7 +209,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value);
|
||||
m_backend.log(identifier, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,7 +222,7 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value, struct);
|
||||
m_backend.log(identifier, value, struct);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -235,6 +235,6 @@ public class LazyLogger implements DataLogger {
|
||||
}
|
||||
|
||||
m_previousValues.put(identifier, value);
|
||||
m_logger.log(identifier, value, struct);
|
||||
m_backend.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
@@ -18,24 +18,24 @@ import java.util.function.LongConsumer;
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/** A sendable builder implementation that sends data to a {@link DataLogger}. */
|
||||
@SuppressWarnings("PMD.CouplingBetweenObjects") // most methods simply delegate to the logger
|
||||
/** A sendable builder implementation that sends data to a {@link EpilogueBackend}. */
|
||||
@SuppressWarnings("PMD.CouplingBetweenObjects") // most methods simply delegate to the backend
|
||||
public class LogBackedSendableBuilder implements SendableBuilder {
|
||||
private final DataLogger m_logger;
|
||||
private final EpilogueBackend m_backend;
|
||||
private final Collection<Runnable> m_updates = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Creates a new sendable builder that delegates writes to an underlying data logger.
|
||||
* Creates a new sendable builder that delegates writes to an underlying backend.
|
||||
*
|
||||
* @param logger the data logger to write the sendable data to
|
||||
* @param backend the backend to write the sendable data to
|
||||
*/
|
||||
public LogBackedSendableBuilder(DataLogger logger) {
|
||||
this.m_logger = logger;
|
||||
public LogBackedSendableBuilder(EpilogueBackend backend) {
|
||||
this.m_backend = backend;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSmartDashboardType(String type) {
|
||||
m_logger.log(".type", type);
|
||||
m_backend.log(".type", type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,132 +50,132 @@ public class LogBackedSendableBuilder implements SendableBuilder {
|
||||
|
||||
@Override
|
||||
public void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsBoolean()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsBoolean()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstBoolean(String key, boolean value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIntegerProperty(String key, LongSupplier getter, LongConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsLong()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsLong()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstInteger(String key, long value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFloatProperty(String key, FloatSupplier getter, FloatConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsFloat()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsFloat()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstFloat(String key, float value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.getAsDouble()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.getAsDouble()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstDouble(String key, double value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstString(String key, String value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBooleanArrayProperty(
|
||||
String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstBooleanArray(String key, boolean[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIntegerArrayProperty(
|
||||
String key, Supplier<long[]> getter, Consumer<long[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstIntegerArray(String key, long[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFloatArrayProperty(
|
||||
String key, Supplier<float[]> getter, Consumer<float[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstFloatArray(String key, float[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDoubleArrayProperty(
|
||||
String key, Supplier<double[]> getter, Consumer<double[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstDoubleArray(String key, double[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStringArrayProperty(
|
||||
String key, Supplier<String[]> getter, Consumer<String[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstStringArray(String key, String[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRawProperty(
|
||||
String key, String typeString, Supplier<byte[]> getter, Consumer<byte[]> setter) {
|
||||
if (getter != null) {
|
||||
m_updates.add(() -> m_logger.log(key, getter.get()));
|
||||
m_updates.add(() -> m_backend.log(key, getter.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishConstRaw(String key, String typeString, byte[] value) {
|
||||
m_logger.log(key, value);
|
||||
m_backend.log(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A backend implementation that delegates to other backends. Helpful for simultaneous logging to
|
||||
* multiple data stores at once.
|
||||
*/
|
||||
public class MultiBackend implements EpilogueBackend {
|
||||
private final List<EpilogueBackend> m_backends;
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
// Use EpilogueBackend.multi(...) instead of instantiation directly
|
||||
MultiBackend(EpilogueBackend... backends) {
|
||||
this.m_backends = List.of(backends);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, byte[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String[] value) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S value, Struct<S> struct) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S[] value, Struct<S> struct) {
|
||||
for (EpilogueBackend backend : m_backends) {
|
||||
backend.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data logger implementation that delegates to other loggers. Helpful for simultaneous logging to
|
||||
* multiple data stores at once.
|
||||
*/
|
||||
public class MultiLogger implements DataLogger {
|
||||
private final List<DataLogger> m_loggers;
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
|
||||
// Use DataLogger.multi(...) instead of instantiation directly
|
||||
MultiLogger(DataLogger... loggers) {
|
||||
this.m_loggers = List.of(loggers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, byte[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, int[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, long[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, float[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, double[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, boolean[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String identifier, String[] value) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S value, Struct<S> struct) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> void log(String identifier, S[] value, Struct<S> struct) {
|
||||
for (DataLogger logger : m_loggers) {
|
||||
logger.log(identifier, value, struct);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,27 +24,27 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data logger implementation that sends data over network tables. Be careful when using this,
|
||||
* since sending too much data may cause bandwidth or CPU starvation.
|
||||
* A backend implementation that sends data over network tables. Be careful when using this, since
|
||||
* sending too much data may cause bandwidth or CPU starvation.
|
||||
*/
|
||||
public class NTDataLogger implements DataLogger {
|
||||
public class NTEpilogueBackend implements EpilogueBackend {
|
||||
private final NetworkTableInstance m_nt;
|
||||
|
||||
private final Map<String, Publisher> m_publishers = new HashMap<>();
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a data logger that sends information to NetworkTables.
|
||||
* Creates a logging backend that sends information to NetworkTables.
|
||||
*
|
||||
* @param nt the NetworkTable instance to use to send data to
|
||||
*/
|
||||
public NTDataLogger(NetworkTableInstance nt) {
|
||||
public NTEpilogueBackend(NetworkTableInstance nt) {
|
||||
this.m_nt = nt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -9,21 +9,21 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A data logger that logs to an underlying logger, prepending all logged data with a specific
|
||||
* prefix. Useful for logging nested data structures.
|
||||
* A backend that logs to an underlying backend, prepending all logged data with a specific prefix.
|
||||
* Useful for logging nested data structures.
|
||||
*/
|
||||
public class SubLogger implements DataLogger {
|
||||
public class NestedBackend implements EpilogueBackend {
|
||||
private final String m_prefix;
|
||||
private final DataLogger m_impl;
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final EpilogueBackend m_impl;
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new sublogger underneath another logger.
|
||||
* Creates a new nested backed underneath another backend.
|
||||
*
|
||||
* @param prefix the prefix to append to all data logged in the sublogger
|
||||
* @param impl the data logger to log to
|
||||
* @param prefix the prefix to append to all data logged in the nested backend
|
||||
* @param impl the backend to log to
|
||||
*/
|
||||
public SubLogger(String prefix, DataLogger impl) {
|
||||
public NestedBackend(String prefix, EpilogueBackend impl) {
|
||||
// Add a trailing slash if not already present
|
||||
if (prefix.endsWith("/")) {
|
||||
this.m_prefix = prefix;
|
||||
@@ -34,8 +34,8 @@ public class SubLogger implements DataLogger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -6,14 +6,14 @@ package edu.wpi.first.epilogue.logging;
|
||||
|
||||
import edu.wpi.first.util.struct.Struct;
|
||||
|
||||
/** Null data logger implementation that logs nothing. */
|
||||
public class NullLogger implements DataLogger {
|
||||
/** Null backend implementation that logs nothing. */
|
||||
public class NullBackend implements EpilogueBackend {
|
||||
/** Default constructor. */
|
||||
public NullLogger() {}
|
||||
public NullBackend() {}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
// Since a sublogger would still log nothing and has no state, we can just return the same
|
||||
public EpilogueBackend getNested(String path) {
|
||||
// Since a nested backend would still log nothing and has no state, we can just return the same
|
||||
// null-logging implementation
|
||||
return this;
|
||||
}
|
||||
@@ -19,10 +19,10 @@ class ClassSpecificLoggerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(DataLogger dataLogger, Point2d object) {
|
||||
dataLogger.log("x", object.x);
|
||||
dataLogger.log("y", object.y);
|
||||
dataLogger.log("dim", object.dim);
|
||||
protected void update(EpilogueBackend backend, Point2d object) {
|
||||
backend.log("x", object.x);
|
||||
backend.log("y", object.y);
|
||||
backend.log("dim", object.dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,14 +31,14 @@ class ClassSpecificLoggerTest {
|
||||
void testReadPrivate() {
|
||||
var point = new Point2d(1, 4, 2);
|
||||
var logger = new Point2d.Logger();
|
||||
var dataLog = new TestLogger();
|
||||
logger.update(dataLog.getSubLogger("Point"), point);
|
||||
var dataLog = new TestBackend();
|
||||
logger.update(dataLog.getNested("Point"), point);
|
||||
|
||||
assertEquals(
|
||||
List.of(
|
||||
new TestLogger.LogEntry<>("Point/x", 1.0),
|
||||
new TestLogger.LogEntry<>("Point/y", 4.0),
|
||||
new TestLogger.LogEntry<>("Point/dim", 2)),
|
||||
new TestBackend.LogEntry<>("Point/x", 1.0),
|
||||
new TestBackend.LogEntry<>("Point/y", 4.0),
|
||||
new TestBackend.LogEntry<>("Point/dim", 2)),
|
||||
dataLog.getEntries());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,36 +10,36 @@ import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LazyLoggerTest {
|
||||
class LazyBackendTest {
|
||||
@Test
|
||||
void lazyOfLazyReturnsSelf() {
|
||||
var lazy = new LazyLogger(new NullLogger());
|
||||
var lazy = new LazyBackend(new NullBackend());
|
||||
assertSame(lazy, lazy.lazy());
|
||||
}
|
||||
|
||||
@Test
|
||||
void lazyInt() {
|
||||
var logger = new TestLogger();
|
||||
var lazy = new LazyLogger(logger);
|
||||
var backend = new TestBackend();
|
||||
var lazy = new LazyBackend(backend);
|
||||
|
||||
{
|
||||
// First time logging to "int" should go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(List.of(new TestLogger.LogEntry<>("int", 0)), logger.getEntries());
|
||||
assertEquals(List.of(new TestBackend.LogEntry<>("int", 0)), backend.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging the current value shouldn't go through
|
||||
lazy.log("int", 0);
|
||||
assertEquals(List.of(new TestLogger.LogEntry<>("int", 0)), logger.getEntries());
|
||||
assertEquals(List.of(new TestBackend.LogEntry<>("int", 0)), backend.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
// Logging a new value should go through
|
||||
lazy.log("int", 1);
|
||||
assertEquals(
|
||||
List.of(new TestLogger.LogEntry<>("int", 0), new TestLogger.LogEntry<>("int", 1)),
|
||||
logger.getEntries());
|
||||
List.of(new TestBackend.LogEntry<>("int", 0), new TestBackend.LogEntry<>("int", 1)),
|
||||
backend.getEntries());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -47,10 +47,10 @@ class LazyLoggerTest {
|
||||
lazy.log("int", 0);
|
||||
assertEquals(
|
||||
List.of(
|
||||
new TestLogger.LogEntry<>("int", 0),
|
||||
new TestLogger.LogEntry<>("int", 1),
|
||||
new TestLogger.LogEntry<>("int", 0)),
|
||||
logger.getEntries());
|
||||
new TestBackend.LogEntry<>("int", 0),
|
||||
new TestBackend.LogEntry<>("int", 1),
|
||||
new TestBackend.LogEntry<>("int", 0)),
|
||||
backend.getEntries());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("PMD.TestClassWithoutTestCases") // This is not a test class!
|
||||
public class TestLogger implements DataLogger {
|
||||
public class TestBackend implements EpilogueBackend {
|
||||
public record LogEntry<T>(String identifier, T value) {}
|
||||
|
||||
private final Map<String, SubLogger> m_subLoggers = new HashMap<>();
|
||||
private final Map<String, NestedBackend> m_nestedBackends = new HashMap<>();
|
||||
|
||||
private final List<LogEntry<?>> m_entries = new ArrayList<>();
|
||||
|
||||
@@ -24,8 +24,8 @@ public class TestLogger implements DataLogger {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLogger getSubLogger(String path) {
|
||||
return m_subLoggers.computeIfAbsent(path, k -> new SubLogger(k, this));
|
||||
public EpilogueBackend getNested(String path) {
|
||||
return m_nestedBackends.computeIfAbsent(path, k -> new NestedBackend(k, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
Reference in New Issue
Block a user