[backend] Logging additions (#24)

* Remove de_pest log level, add instanced shouldLog

* Rename Server, VisionProcess LogGroup to WebServer, VisionModule

* Rename Level to LogLevel

* Added lambda logger methods

* Updated Platform util class, added bootup logging

* Naming fix

* Fix errors, apply spotless

* Apply spotless
This commit is contained in:
Banks T
2020-07-11 22:43:19 -04:00
committed by GitHub
parent a3ee9d8977
commit 9f1899b081
15 changed files with 148 additions and 110 deletions

View File

@@ -17,16 +17,17 @@
package org.photonvision;
import edu.wpi.cscore.CameraServerCvJNI;
import java.util.HashMap;
import java.util.List;
import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.datatransfer.networktables.NetworkTablesManager;
import org.photonvision.common.logging.Level;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.LogLevel;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.networking.NetworkManager;
import org.photonvision.common.util.TestUtils;
import org.photonvision.common.util.Platform;
import org.photonvision.server.Server;
import org.photonvision.vision.camera.USBCameraSource;
import org.photonvision.vision.pipeline.CVPipelineSettings;
@@ -36,33 +37,59 @@ import org.photonvision.vision.processes.VisionSourceManager;
public class Main {
private static final Logger logger = new Logger(Main.class, LogGroup.General);
public static final int DEFAULT_WEBPORT = 5800;
public static void main(String[] args) {
Logger.setLevel(LogGroup.Camera, Level.DE_PEST);
Logger.setLevel(LogGroup.Server, Level.DE_PEST);
Logger.setLevel(LogGroup.VisionProcess, Level.DE_PEST);
Logger.setLevel(LogGroup.Data, Level.DE_PEST);
Logger.setLevel(LogGroup.General, Level.DE_PEST);
private static String getVersion() {
return "2020.7.1"; // TODO: grab from gradle/resource somehow
}
public static void main(String[] args) {
Logger.setLevel(LogGroup.Camera, LogLevel.TRACE);
Logger.setLevel(LogGroup.WebServer, LogLevel.TRACE);
Logger.setLevel(LogGroup.VisionModule, LogLevel.TRACE);
Logger.setLevel(LogGroup.Data, LogLevel.TRACE);
Logger.setLevel(LogGroup.General, LogLevel.TRACE);
logger.info("Logging initialized!");
logger.info(
"Starting PhotonVision version "
+ getVersion()
+ " on "
+ Platform.CurrentPlatform.toString());
try {
logger.info("Loading native libraries...");
CameraServerCvJNI.forceLoad();
} catch (Exception e) {
logger.error("Failed to load native libraries!");
e.printStackTrace(); // TODO: redirect stacktrace to Logger stream somehow
}
logger.info("Native libaries loaded.");
TestUtils.loadLibraries();
ConfigManager.getInstance(); // init config manager
NetworkManager.getInstance().initialize(false); // basically empty. todo: link to ConfigManager?
NetworkTablesManager.setClientMode("127.0.0.1");
HashMap<String, CameraConfiguration> camConfigs =
ConfigManager.getInstance().getConfig().getCameraConfigurations();
logger.info("Loaded " + camConfigs.size() + " configs from disk!");
logger.info("Loaded " + camConfigs.size() + " configs from disk.");
List<VisionSource> sources = VisionSourceManager.loadAllSources(camConfigs.values());
var collectedSources = new HashMap<VisionSource, List<CVPipelineSettings>>();
for (var src : sources) {
var usbSrc = (USBCameraSource) src;
collectedSources.put(usbSrc, usbSrc.configuration.pipelineSettings);
logger.trace(
() -> {
return "Matched config for camera \""
+ src.getFrameProvider().getName()
+ "\" and loaded "
+ usbSrc.configuration.pipelineSettings.size()
+ " pipelines";
});
}
logger.info("Adding " + collectedSources.size() + " configs to VMM");
logger.info("Adding " + collectedSources.size() + " configs to VMM.");
VisionModuleManager.getInstance().addSources(collectedSources);
ConfigManager.getInstance().addCameraConfigurations(collectedSources);

View File

@@ -229,7 +229,7 @@ public class ConfigManager {
driverModeFile.toAbsolutePath(), DriverModePipelineSettings.class);
} catch (JsonProcessingException e) {
logger.error("Could not deserialize drivermode.json! Loading defaults");
logger.de_pest(Arrays.toString(e.getStackTrace()));
logger.trace(Arrays.toString(e.getStackTrace()));
driverMode = new DriverModePipelineSettings();
}
if (driverMode == null) {

View File

@@ -22,14 +22,13 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;
import org.photonvision.common.dataflow.events.DataChangeEvent;
import org.photonvision.common.logging.Level;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
@SuppressWarnings("rawtypes")
public class DataChangeService {
private static final Logger logger = new Logger(DataChangeService.class, LogGroup.Server);
private static final Logger logger = new Logger(DataChangeService.class, LogGroup.WebServer);
private static class ThreadSafeSingleton {
private static final DataChangeService INSTANCE = new DataChangeService();
@@ -78,16 +77,19 @@ public class DataChangeService {
if (!subscribers.addIfAbsent(subscriber)) {
logger.warn("Attempted to add already added subscriber!");
} else {
if (Logger.shouldLog(Level.TRACE, LogGroup.Data)) {
var sources =
subscriber.wantedSources.stream().map(Enum::toString).collect(Collectors.joining(", "));
var dests =
subscriber.wantedDestinations.stream()
.map(Enum::toString)
.collect(Collectors.joining(", "));
logger.trace(
() -> {
var sources =
subscriber.wantedSources.stream()
.map(Enum::toString)
.collect(Collectors.joining(", "));
var dests =
subscriber.wantedDestinations.stream()
.map(Enum::toString)
.collect(Collectors.joining(", "));
logger.trace("Added subscriber - " + "Sources: " + sources + ", Destinations: " + dests);
}
return "Added subscriber - " + "Sources: " + sources + ", Destinations: " + dests;
});
}
}

View File

@@ -35,7 +35,7 @@ public class IncomingCameraCommandSubscriber extends DataChangeSubscriber {
@Override
public void onDataChangeEvent(DataChangeEvent event) {
// logger.de_pest("Got event from [" + event.sourceType + "] and dest [" + event.destType
// logger.trace("Got event from [" + event.sourceType + "] and dest [" + event.destType
// + "] with property name [" + event.propertyName
// + "] and value [" + event.data + "]");
}

View File

@@ -19,8 +19,8 @@ package org.photonvision.common.logging;
public enum LogGroup {
Camera,
Server,
VisionProcess,
WebServer,
VisionModule,
Data,
General
}

View File

@@ -17,19 +17,18 @@
package org.photonvision.common.logging;
public enum Level {
public enum LogLevel {
OFF(0, Logger.ANSI_BLACK),
ERROR(1, Logger.ANSI_RED),
WARN(2, Logger.ANSI_YELLOW),
INFO(3, Logger.ANSI_GREEN),
DEBUG(4, Logger.ANSI_WHITE),
TRACE(5, Logger.ANSI_CYAN),
DE_PEST(6, Logger.ANSI_WHITE);
TRACE(5, Logger.ANSI_CYAN);
public final String colorCode;
public final int code;
Level(int code, String colorCode) {
LogLevel(int code, String colorCode) {
this.code = code;
this.colorCode = colorCode;
}

View File

@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.function.Supplier;
import org.photonvision.common.dataflow.DataChangeService;
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
import org.photonvision.server.UIUpdateType;
@@ -64,7 +65,7 @@ public class Logger {
}
public static String format(
String logMessage, Level level, LogGroup group, String clazz, boolean color) {
String logMessage, LogLevel level, LogGroup group, String clazz, boolean color) {
var date = getDate();
var builder = new StringBuilder();
if (color) builder.append(level.colorCode);
@@ -83,19 +84,19 @@ public class Logger {
return builder.toString();
}
private static HashMap<LogGroup, Level> levelMap = new HashMap<>();
private static List<Appender> currentAppenders = new ArrayList<>();
private static HashMap<LogGroup, LogLevel> levelMap = new HashMap<>();
private static List<LogAppender> currentAppenders = new ArrayList<>();
static {
levelMap.put(LogGroup.Camera, Level.INFO);
levelMap.put(LogGroup.General, Level.INFO);
levelMap.put(LogGroup.Server, Level.INFO);
levelMap.put(LogGroup.Data, Level.INFO);
levelMap.put(LogGroup.VisionProcess, Level.INFO);
levelMap.put(LogGroup.Camera, LogLevel.INFO);
levelMap.put(LogGroup.General, LogLevel.INFO);
levelMap.put(LogGroup.WebServer, LogLevel.INFO);
levelMap.put(LogGroup.Data, LogLevel.INFO);
levelMap.put(LogGroup.VisionModule, LogLevel.INFO);
}
static {
currentAppenders.add(new ConsoleAppender());
currentAppenders.add(new ConsoleLogAppender());
currentAppenders.add(new UILogAppender());
}
@@ -109,63 +110,92 @@ public class Logger {
e.printStackTrace();
}
}
currentAppenders.add(new AsyncFileAppender(logFilePath));
currentAppenders.add(new AsyncFileLogAppender(logFilePath));
}
public static void setLevel(LogGroup group, Level newLevel) {
public static void setLevel(LogGroup group, LogLevel newLevel) {
levelMap.put(group, newLevel);
}
private static void log(String message, Level level, LogGroup group, String clazz) {
// TODO: profile
private static void log(String message, LogLevel level, LogGroup group, String clazz) {
for (var a : currentAppenders) {
var shouldColor = a instanceof ConsoleAppender;
var shouldColor = a instanceof ConsoleLogAppender;
var formattedMessage = format(message, level, group, clazz, shouldColor);
a.log(formattedMessage);
}
}
public static boolean shouldLog(Level logLevel, LogGroup group) {
public boolean shouldLog(LogLevel logLevel) {
return logLevel.code <= levelMap.get(group).code;
}
private void log(String message, LogLevel level) {
if (shouldLog(level)) {
log(message, level, group, className);
}
}
private void log(Supplier<String> messageSupplier, LogLevel level) {
if (shouldLog(level)) {
log(messageSupplier.get(), level, group, className);
}
}
public void error(Supplier<String> messageSupplier) {
log(messageSupplier, LogLevel.ERROR);
}
public void error(String message) {
if (shouldLog(Level.ERROR, group)) log(message, Level.ERROR, group, className);
log(message, LogLevel.ERROR);
}
public void warn(Supplier<String> messageSupplier) {
log(messageSupplier, LogLevel.WARN);
}
public void warn(String message) {
if (shouldLog(Level.WARN, group)) log(message, Level.WARN, group, className);
log(message, LogLevel.WARN);
}
public void info(Supplier<String> messageSupplier) {
log(messageSupplier, LogLevel.INFO);
}
public void info(String message) {
if (shouldLog(Level.INFO, group)) log(message, Level.INFO, group, className);
log(message, LogLevel.INFO);
}
public void debug(Supplier<String> messageSupplier) {
log(messageSupplier, LogLevel.DEBUG);
}
public void debug(String message) {
if (shouldLog(Level.DEBUG, group)) log(message, Level.DEBUG, group, className);
log(message, LogLevel.DEBUG);
}
public void trace(Supplier<String> messageSupplier) {
log(messageSupplier, LogLevel.TRACE);
}
public void trace(String message) {
if (shouldLog(Level.TRACE, group)) log(message, Level.TRACE, group, className);
log(message, LogLevel.TRACE);
}
public void de_pest(String message) {
if (shouldLog(Level.DE_PEST, group)) log(message, Level.DE_PEST, group, className);
private interface LogAppender {
void log(String message);
}
private abstract static class Appender {
abstract void log(String message);
}
private static class ConsoleAppender extends Appender {
private static class ConsoleLogAppender implements LogAppender {
@Override
void log(String message) {
public void log(String message) {
System.out.println(message);
}
}
private static class UILogAppender extends Appender {
private static class UILogAppender implements LogAppender {
@Override
void log(String message) {
public void log(String message) {
var message_ = new HashMap<>();
message_.put("logMessage", message);
DataChangeService.getInstance()
@@ -173,15 +203,15 @@ public class Logger {
}
}
private static class AsyncFileAppender extends Appender {
private static class AsyncFileLogAppender implements LogAppender {
private final Path filePath;
public AsyncFileAppender(Path logFilePath) {
public AsyncFileLogAppender(Path logFilePath) {
this.filePath = logFilePath;
}
@Override
void log(String message) {
public void log(String message) {
try (AsynchronousFileChannel asyncFile =
AsynchronousFileChannel.open(
filePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {

View File

@@ -19,23 +19,21 @@ package org.photonvision.common.util;
import edu.wpi.first.wpiutil.RuntimeDetector;
import java.io.IOException;
import org.apache.commons.lang3.SystemUtils;
@SuppressWarnings("unused")
public enum Platform {
// WPILib Supported (JNI)
WINDOWS_32("Windows x32"),
WINDOWS_64("Windows x64"),
LINUX_32("Linux x32"),
LINUX_64("Linux x64"),
LINUX_RASPBIAN("Linux Raspbian"), // Raspberry Pi 3/4
LINUX_AARCH64BIONIC("Linux AARCH64 Bionic"), // Jetson Nano, Jetson TX2
MACOS_64("Mac OS x64"),
// ChameleonVision Supported (Manual install)
LINUX_ARM32("Linux ARM32"), // ODROID XU4, C1+
LINUX_ARM64("Linux ARM64"), // ODROID C2, N2
// Completely unsupported
UNSUPPORTED("Unsupported Platform");
LINUX_RASPBIAN("Linux Raspbian"), // TODO: check that RaspiOS reports the same way
LINUX_AARCH64BIONIC("Linux Aarch64 Bionic"),
UNSUPPORTED(
"Unsupported Platform - OS: "
+ SystemUtils.OS_NAME
+ ", Architecture: "
+ SystemUtils.OS_ARCH);
public final String value;
public final boolean isRoot = checkForRoot();
@@ -44,23 +42,14 @@ public enum Platform {
this.value = value;
}
private static final String OS_NAME = System.getProperty("os.name");
private static final String OS_ARCH = System.getProperty("os.arch");
public static final Platform CurrentPlatform = getCurrentPlatform();
private static String UnknownPlatformString =
String.format("Unknown Platform. OS: %s, Architecture: %s", OS_NAME, OS_ARCH);
public boolean isWindows() {
return this == WINDOWS_64 || this == WINDOWS_32;
public static boolean isWindows() {
return CurrentPlatform == WINDOWS_64 || CurrentPlatform == WINDOWS_32;
}
public boolean isLinux() {
return this == LINUX_64 || this == LINUX_RASPBIAN || this == LINUX_ARM64;
}
public boolean isMac() {
return this == MACOS_64;
public static boolean isLinux() {
return CurrentPlatform != UNSUPPORTED && !isWindows();
}
public static boolean isRaspberryPi() {
@@ -71,7 +60,7 @@ public enum Platform {
@SuppressWarnings("StatementWithEmptyBody")
private boolean checkForRoot() {
if (isLinux() || isMac()) {
if (isLinux()) {
try {
shell.execute("id", null, true, "-u");
} catch (IOException e) {
@@ -98,26 +87,17 @@ public enum Platform {
if (RuntimeDetector.is64BitIntel()) return WINDOWS_64;
}
if (RuntimeDetector.isMac()) {
if (RuntimeDetector.is32BitIntel()) return UNSUPPORTED;
if (RuntimeDetector.is64BitIntel()) return MACOS_64;
}
if (RuntimeDetector.isLinux()) {
if (RuntimeDetector.is32BitIntel()) return UNSUPPORTED;
if (RuntimeDetector.is32BitIntel()) return LINUX_32;
if (RuntimeDetector.is64BitIntel()) return LINUX_64;
if (RuntimeDetector.isRaspbian()) return LINUX_RASPBIAN;
if (RuntimeDetector.isAarch64Bionic()) return LINUX_AARCH64BIONIC;
}
System.out.println(UnknownPlatformString);
return Platform.UNSUPPORTED;
return UNSUPPORTED;
}
public String toString() {
if (this.equals(UNSUPPORTED)) {
return UnknownPlatformString;
} else {
return this.value;
}
return this.value;
}
}

View File

@@ -22,7 +22,7 @@ import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
public class Server {
private static final Logger logger = new Logger(Server.class, LogGroup.Server);
private static final Logger logger = new Logger(Server.class, LogGroup.WebServer);
public static void main(int port) {

View File

@@ -39,7 +39,7 @@ import org.photonvision.vision.processes.VisionModuleManager;
@SuppressWarnings("rawtypes")
public class SocketHandler {
private final Logger logger = new Logger(SocketHandler.class, LogGroup.Server);
private final Logger logger = new Logger(SocketHandler.class, LogGroup.WebServer);
private final List<WsContext> users = new ArrayList<>();
private final ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
private final DataChangeService dcService = DataChangeService.getInstance();

View File

@@ -34,7 +34,7 @@ import org.photonvision.common.logging.Logger;
* DO NOT use logging in this class. If you do, the logs will recuse forever!
*/
class UIOutboundSubscriber extends DataChangeSubscriber {
Logger logger = new Logger(UIOutboundSubscriber.class, LogGroup.Server);
Logger logger = new Logger(UIOutboundSubscriber.class, LogGroup.WebServer);
private final SocketHandler socketHandler;

View File

@@ -26,7 +26,7 @@ import org.photonvision.vision.pipeline.*;
@SuppressWarnings({"rawtypes", "unused"})
public class PipelineManager {
private static final Logger logger = new Logger(PipelineManager.class, LogGroup.VisionProcess);
private static final Logger logger = new Logger(PipelineManager.class, LogGroup.VisionModule);
public static final int DRIVERMODE_INDEX = -1;
public static final int CAL_3D_INDEX = -2;

View File

@@ -70,7 +70,7 @@ public class VisionModule {
new Logger(
VisionModule.class,
visionSource.getSettables().getConfiguration().nickname,
LogGroup.VisionProcess);
LogGroup.VisionModule);
this.pipelineManager = pipelineManager;
this.visionSource = visionSource;
this.visionRunner =

View File

@@ -56,7 +56,7 @@ public class VisionRunner {
visionProcessThread = new Thread(this::update);
visionProcessThread.setName("VisionRunner - " + frameSupplier.getName());
logger = new Logger(VisionRunner.class, frameSupplier.getName(), LogGroup.VisionProcess);
logger = new Logger(VisionRunner.class, frameSupplier.getName(), LogGroup.VisionModule);
}
public void startProcess() {