diff --git a/include/cscore_c.h b/include/cscore_c.h index e46103a6b9..44c09fb11d 100644 --- a/include/cscore_c.h +++ b/include/cscore_c.h @@ -54,6 +54,21 @@ enum CS_StatusValue { CS_SOURCE_IS_DISCONNECTED = -2005 }; +// +// Logging levels +// +enum CS_LogLevel { + CS_LOG_CRITICAL = 50, + CS_LOG_ERROR = 40, + CS_LOG_WARNING = 30, + CS_LOG_INFO = 20, + CS_LOG_DEBUG = 10, + CS_LOG_DEBUG1 = 9, + CS_LOG_DEBUG2 = 8, + CS_LOG_DEBUG3 = 7, + CS_LOG_DEBUG4 = 6 +}; + // // Pixel formats // @@ -285,6 +300,13 @@ void CS_RemoveListener(CS_Listener handle, CS_Status* status); int CS_NotifierDestroyed(void); +// +// Logging Functions +// +typedef void (*CS_LogFunc)(unsigned int level, const char* file, + unsigned int line, const char* msg); +void CS_SetLogger(CS_LogFunc func, unsigned int min_level); + // // Utility Functions // diff --git a/include/cscore_cpp.h b/include/cscore_cpp.h index 4dd2786dbf..b8256c166b 100644 --- a/include/cscore_cpp.h +++ b/include/cscore_cpp.h @@ -278,6 +278,14 @@ void RemoveListener(CS_Listener handle, CS_Status* status); bool NotifierDestroyed(); +// +// Logging Functions +// +typedef std::function + LogFunc; +void SetLogger(LogFunc func, unsigned int min_level); + // // Utility Functions // diff --git a/java/lib/CameraServerJNI.cpp b/java/lib/CameraServerJNI.cpp index 2759d271e5..b6d7abd108 100644 --- a/java/lib/CameraServerJNI.cpp +++ b/java/lib/CameraServerJNI.cpp @@ -1154,3 +1154,67 @@ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_getNetworkInt } } // extern "C" + +namespace { + +struct LogMessage { + public: + LogMessage(unsigned int level, const char *file, unsigned int line, + const char *msg) + : m_level(level), m_file(file), m_line(line), m_msg(msg) {} + + void CallJava(JNIEnv* env, jobject func, jmethodID mid) { + JLocal file{env, MakeJString(env, m_file)}; + JLocal msg{env, MakeJString(env, m_msg)}; + env->CallVoidMethod(func, mid, (jint)m_level, file.obj(), + (jint)m_line, msg.obj()); + } + + static const char* GetName() { return "NTLogger"; } + static JavaVM* GetJVM() { return jvm; } + + private: + unsigned int m_level; + const char* m_file; + unsigned int m_line; + std::string m_msg; +}; + +typedef JSingletonCallbackManager LoggerJNI; + +} // anonymous namespace + +ATOMIC_STATIC_INIT(LoggerJNI) + +extern "C" { + +/* + * Class: edu_wpi_cscore_CameraServerJNI + * Method: setLogger + * Signature: (Ledu/wpi/cscore/CameraServerJNI/LoggerFunction;I)V + */ +JNIEXPORT void JNICALL Java_edu_wpi_cscore_CameraServerJNI_setLogger + (JNIEnv *env, jclass, jobject func, jint minLevel) +{ + // cls is a temporary here; cannot be used within callback functor + jclass cls = env->GetObjectClass(func); + if (!cls) return; + + // method ids, on the other hand, are safe to retain + jmethodID mid = env->GetMethodID( + cls, "apply", "(ILjava/lang/String;ILjava/lang/String;)V"); + if (!mid) return; + + auto& logger = LoggerJNI::GetInstance(); + logger.Start(); + logger.SetFunc(env, func, mid); + + cs::SetLogger( + [](unsigned int level, const char *file, unsigned int line, + const char *msg) { + LoggerJNI::GetInstance().Send(level, file, line, msg); + }, + minLevel); +} + +} // extern "C" diff --git a/java/src/edu/wpi/cscore/CameraServerJNI.java b/java/src/edu/wpi/cscore/CameraServerJNI.java index 3ed058e980..c846885de6 100644 --- a/java/src/edu/wpi/cscore/CameraServerJNI.java +++ b/java/src/edu/wpi/cscore/CameraServerJNI.java @@ -184,6 +184,15 @@ public class CameraServerJNI { public static native void removeListener(int handle); + // + // Logging Functions + // + @FunctionalInterface + public interface LoggerFunction { + void apply(int level, String file, int line, String msg); + } + public static native void setLogger(LoggerFunction func, int minLevel); + // // Utility Functions // diff --git a/src/cscore_c.cpp b/src/cscore_c.cpp index d1aecaa341..7b763daab6 100644 --- a/src/cscore_c.cpp +++ b/src/cscore_c.cpp @@ -265,6 +265,10 @@ void CS_RemoveListener(CS_Listener handle, CS_Status* status) { int CS_NotifierDestroyed(void) { return cs::NotifierDestroyed(); } +void CS_SetLogger(CS_LogFunc func, unsigned int min_level) { + cs::SetLogger(func, min_level); +} + CS_Source* CS_EnumerateSources(int* count, CS_Status* status) { llvm::SmallVector buf; auto handles = cs::EnumerateSourceHandles(buf, status); diff --git a/src/cscore_cpp.cpp b/src/cscore_cpp.cpp index 6cc01a8ab2..ad51ca5fee 100644 --- a/src/cscore_cpp.cpp +++ b/src/cscore_cpp.cpp @@ -16,6 +16,7 @@ #include "llvm/SmallString.h" +#include "Log.h" #include "NetworkListener.h" #include "Notifier.h" #include "SinkImpl.h" @@ -511,6 +512,15 @@ void RemoveListener(CS_Listener handle, CS_Status* status) { bool NotifierDestroyed() { return Notifier::destroyed(); } +// +// Logging Functions +// +void SetLogger(LogFunc func, unsigned int min_level) { + Logger& logger = Logger::GetInstance(); + logger.SetLogger(func); + logger.set_min_level(min_level); +} + // // Utility Functions //