From 9d587d57461cdba8925710b47addcf8dc1d88995 Mon Sep 17 00:00:00 2001 From: Craig Schardt Date: Fri, 19 Dec 2025 20:35:18 -0600 Subject: [PATCH] Log fewer errors (#2246) ## Description We currently log some things with ERROR status and include stack traces for events that are typical behavior. This pollutes the logs and makes it harder to track down real errors. This PR changes the way that some events are logged: * missing configs in the database are logged as [INFO] without the exception stack trace. * skip parsing NPU usage when the command is blank so that it doesn't throw a NumberFormatException. * log warn instead of error for unsupported NN backends (added by @samfreund) * skip warn when we don't add a model, only debug when we add it (added by @samfreund) Before: ``` Oct 22 20:56:26 photonvision java[831]: [2024-10-22 20:56:26] [Config - SqlConfigProvider] [ERROR] Could not deserialize apriltag layout! Loading defaults: Provided empty string for class edu.wpi.first.apriltag.AprilTagFieldLayout Oct 22 20:56:26 photonvision java[831]: [2024-10-22 20:56:26] [Config - SqlConfigProvider] [ERROR] org.eclipse.jetty.io.EofException: Provided empty string for class edu.wpi.first.apriltag.AprilTagFieldLayout Oct 22 20:56:26 photonvision java[831]: at org.photonvision.common.util.file.JacksonUtils.deserialize(JacksonUtils.java:136) Oct 22 20:56:26 photonvision java[831]: at org.photonvision.common.configuration.SqlConfigProvider.load(SqlConfigProvider.java:298) Oct 22 20:56:26 photonvision java[831]: at org.photonvision.common.configuration.ConfigManager.load(ConfigManager.java:198) Oct 22 20:56:26 photonvision java[831]: at org.photonvision.Main.main(Main.java:290) ``` After: ``` Dec 15 22:29:09 photonvision java[662]: [2025-12-15 22:29:09] [Config - SqlConfigProvider] [INFO] Missing AprilTag Field Layout in database. Loading defaults ``` ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2025.3.2 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: samfreund Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com> --- .../NeuralNetworkModelManager.java | 4 +- .../configuration/SqlConfigProvider.java | 120 +++++++++--------- .../hardware/metrics/MetricsManager.java | 3 + .../src/main/java/org/photonvision/Main.java | 4 +- 4 files changed, 64 insertions(+), 67 deletions(-) diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/NeuralNetworkModelManager.java b/photon-core/src/main/java/org/photonvision/common/configuration/NeuralNetworkModelManager.java index 6b789402e..ec94a9bdd 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/NeuralNetworkModelManager.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/NeuralNetworkModelManager.java @@ -416,9 +416,7 @@ public class NeuralNetworkModelManager { for (ModelProperties model : getShippedProperties(modelsDirectory).getModels()) { if (supportedBackends.contains(model.family())) { supportedProperties.addModelProperties(model); - } else { - logger.warn( - "Skipping model " + model.nickname() + " as it is not supported on this platform."); + logger.debug("Added shipped model: " + model.modelPath().getFileName().toString()); } } diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java b/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java index b9c6c17ec..40d322df9 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/SqlConfigProvider.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Objects; +import java.util.function.Supplier; import java.util.stream.Collectors; import org.photonvision.common.configuration.CameraConfiguration.LegacyCameraConfigStruct; import org.photonvision.common.configuration.DatabaseSchema.Columns; @@ -253,6 +254,45 @@ public class SqlConfigProvider extends ConfigProvider { return true; } + private T loadConfigOrDefault( + Connection conn, String key, Class ref, Supplier factory) { + String configString = getOneConfigFile(conn, key); + T configObj; + if (!configString.isBlank()) { + try { + configObj = JacksonUtils.deserialize(configString, ref); + logger.info("Loaded " + ref.getSimpleName() + " from database"); + return configObj; + } catch (IOException e) { + logger.error("Could not deserialize " + ref.getSimpleName() + " from database!", e); + } + } else { + logger.debug("No " + ref.getSimpleName() + " in database"); + } + // either the config entry is empty or Jackson threw and exception + try { + configObj = factory.get(); + logger.info("Loaded default " + ref.getSimpleName()); + return configObj; + } catch (Exception e) { + logger.error("Failed to construct a default instance of " + ref.getSimpleName(), e); + } + return null; + } + + private AprilTagFieldLayout atflDefault() { + AprilTagFieldLayout atfl; + try { + atfl = AprilTagFieldLayout.loadField(AprilTagFields.kDefaultField); + logger.info("Loaded " + AprilTagFields.kDefaultField.toString() + " field"); + } catch (UncheckedIOException e) { + logger.error("Error loading WPILib field", e); + logger.info("Creating an empty field"); + atfl = new AprilTagFieldLayout(List.of(), 1, 1); + } + return atfl; + } + @Override public void load() { logger.debug("Loading config..."); @@ -260,68 +300,24 @@ public class SqlConfigProvider extends ConfigProvider { if (conn == null) return; synchronized (m_mutex) { - HardwareConfig hardwareConfig; - HardwareSettings hardwareSettings; - NetworkConfig networkConfig; - AprilTagFieldLayout atfl; - NeuralNetworkPropertyManager nnProps; - - try { - hardwareConfig = - JacksonUtils.deserialize( - getOneConfigFile(conn, GlobalKeys.HARDWARE_CONFIG), HardwareConfig.class); - } catch (IOException e) { - logger.error("Could not deserialize hardware config! Loading defaults", e); - hardwareConfig = new HardwareConfig(); - } - - try { - hardwareSettings = - JacksonUtils.deserialize( - getOneConfigFile(conn, GlobalKeys.HARDWARE_SETTINGS), HardwareSettings.class); - } catch (IOException e) { - logger.error("Could not deserialize hardware settings! Loading defaults", e); - hardwareSettings = new HardwareSettings(); - } - - try { - networkConfig = - JacksonUtils.deserialize( - getOneConfigFile(conn, GlobalKeys.NETWORK_CONFIG), NetworkConfig.class); - } catch (IOException e) { - logger.error("Could not deserialize network config! Loading defaults", e); - networkConfig = new NetworkConfig(); - } - - try { - atfl = - JacksonUtils.deserialize( - getOneConfigFile(conn, GlobalKeys.ATFL_CONFIG_FILE), AprilTagFieldLayout.class); - } catch (IOException e) { - logger.error("Could not deserialize apriltag layout! Loading defaults", e); - try { - atfl = AprilTagFieldLayout.loadField(AprilTagFields.kDefaultField); - } catch (UncheckedIOException e2) { - logger.error("Error loading WPILib field", e); - atfl = null; - } - if (atfl == null) { - // what do we even do here lmao -- wpilib should always work - logger.error("Field layout is *still* null??????"); - atfl = new AprilTagFieldLayout(List.of(), 1, 1); - } - } - - try { - nnProps = - JacksonUtils.deserialize( - getOneConfigFile(conn, GlobalKeys.NEURAL_NETWORK_PROPERTIES), - NeuralNetworkPropertyManager.class); - } catch (IOException e) { - logger.error("Could not deserialize neural network properties! Loading defaults", e); - nnProps = new NeuralNetworkPropertyManager(); - } - + var hardwareConfig = + loadConfigOrDefault( + conn, GlobalKeys.HARDWARE_CONFIG, HardwareConfig.class, HardwareConfig::new); + var hardwareSettings = + loadConfigOrDefault( + conn, GlobalKeys.HARDWARE_SETTINGS, HardwareSettings.class, HardwareSettings::new); + var networkConfig = + loadConfigOrDefault( + conn, GlobalKeys.NETWORK_CONFIG, NetworkConfig.class, NetworkConfig::new); + var nnProps = + loadConfigOrDefault( + conn, + GlobalKeys.NEURAL_NETWORK_PROPERTIES, + NeuralNetworkPropertyManager.class, + NeuralNetworkPropertyManager::new); + var atfl = + loadConfigOrDefault( + conn, GlobalKeys.ATFL_CONFIG_FILE, AprilTagFieldLayout.class, this::atflDefault); var cams = loadCameraConfigs(conn); try { diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java index 717c84414..c103c5d18 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java @@ -199,6 +199,9 @@ public class MetricsManager { * @return An array of doubles representing NPU usage, or null if parsing fails. */ public double[] getNpuUsage() { + if (cmds.npuUsageCommand.isBlank()) { + return new double[0]; + } String[] usages = safeExecute(cmds.npuUsageCommand).split(","); double[] usageDoubles = new double[usages.length]; for (int i = 0; i < usages.length; i++) { diff --git a/photon-server/src/main/java/org/photonvision/Main.java b/photon-server/src/main/java/org/photonvision/Main.java index 6191fa501..a5a84a31f 100644 --- a/photon-server/src/main/java/org/photonvision/Main.java +++ b/photon-server/src/main/java/org/photonvision/Main.java @@ -241,13 +241,13 @@ public class Main { if (Platform.isRK3588()) { tryLoadJNI(JNITypes.RKNN_DETECTOR); } else { - logger.error("Platform does not support RKNN based machine learning!"); + logger.warn("Platform does not support RKNN based machine learning!"); } if (Platform.isQCS6490()) { tryLoadJNI(JNITypes.RUBIK_DETECTOR); } else { - logger.error("Platform does not support Rubik based machine learning!"); + logger.warn("Platform does not support Rubik based machine learning!"); } if (Platform.isWindows() || Platform.isLinux()) {