[epilogue] Rename DataLogger to EpilogueBackend for clarity (#7453)

Update documentation and internal names correspondingly
This commit is contained in:
Sam Carlberg
2024-11-30 01:10:51 -05:00
committed by GitHub
parent 65f3345407
commit 806d56e564
29 changed files with 448 additions and 447 deletions

View File

@@ -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

View File

@@ -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;
});

View File

@@ -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.

View File

@@ -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")

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}
}

View File

@@ -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