summaryrefslogtreecommitdiff
path: root/src/core/log.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-04-13 10:59:05 -0700
committerGarrett D'Amore <garrett@damore.org>2024-04-13 20:42:14 -0700
commitdf371e0a77e5b30f5ebddd0902fc8dd46b349849 (patch)
tree50c53add482002f79a2fd49d6881671ee3d7f3cd /src/core/log.c
parentd2ab8a8cf3a93621f853a41b029b40c61b79d0db (diff)
downloadnng-df371e0a77e5b30f5ebddd0902fc8dd46b349849.tar.gz
nng-df371e0a77e5b30f5ebddd0902fc8dd46b349849.tar.bz2
nng-df371e0a77e5b30f5ebddd0902fc8dd46b349849.zip
fixes #543 Add logging support framework
Diffstat (limited to 'src/core/log.c')
-rw-r--r--src/core/log.c284
1 files changed, 284 insertions, 0 deletions
diff --git a/src/core/log.c b/src/core/log.c
new file mode 100644
index 00000000..b560f6c7
--- /dev/null
+++ b/src/core/log.c
@@ -0,0 +1,284 @@
+
+// Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include "nng/nng.h"
+#include "nng_impl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef NNG_PLATFORM_WINDOWS
+#include <io.h>
+#endif
+#ifdef NNG_PLATFORM_POSIX
+#include <syslog.h>
+#include <unistd.h>
+#endif
+#include <time.h>
+
+static nng_log_level log_level = NNG_LOG_NOTICE;
+static nng_log_facility log_facility = NNG_LOG_USER;
+static nng_logger log_logger = nng_null_logger;
+
+void
+nng_log_set_facility(nng_log_facility facility)
+{
+ log_facility = facility;
+}
+
+void
+nng_log_set_level(nng_log_level level)
+{
+ log_level = level;
+}
+
+void
+nng_log_set_logger(nng_logger logger)
+{
+ if (logger == NULL) {
+ logger = nng_null_logger;
+ }
+ log_logger = logger;
+}
+
+void
+nng_null_logger(nng_log_level level, nng_log_facility facility,
+ const char *msgid, const char *msg)
+{
+ NNI_ARG_UNUSED(level);
+ NNI_ARG_UNUSED(facility);
+ NNI_ARG_UNUSED(msgid);
+ NNI_ARG_UNUSED(msg);
+ return;
+}
+
+void
+nng_stderr_logger(nng_log_level level, nng_log_facility facility,
+ const char *msgid, const char *msg)
+{
+ const char *sgr, *sgr0;
+ // Initial implementation.
+ bool colors = false;
+ const char *level_str;
+ time_t now;
+ char when[64];
+ NNI_ARG_UNUSED(facility);
+
+#ifdef NNG_PLATFORM_WINDOWS
+ // NB: We are blithely assuming the user has a modern console.
+ colors = _isatty(_fileno(stderr));
+#elif defined(NNG_PLATFORM_POSIX)
+ // Only assuming we can use colors (and attributes) if stderr is a tty
+ // and $TERM is reasonable. We assume the terminal supports ECMA-48,
+ // which is true on every reasonable system these days.
+ colors = isatty(fileno(stderr)) && (getenv("TERM") != NULL) &&
+ (getenv("TERM")[0] != 0);
+#else
+ now = 0;
+ colors = false;
+#endif
+
+ // Escape hatch to prevent colorizing logs if we have to. Users on
+ // legacy Windows can set this, or on ancient HP terminals or
+ // something. Also in the same way that no-color.org proposes.
+ // The reason for both is to allow suppression *only* for NNG. There
+ // is no good reason to enable it to override the presence of NO_COLOR.
+ if ((getenv("NNG_LOG_NO_COLOR") != NULL) ||
+ (getenv("NO_COLOR") != NULL)) {
+ colors = false;
+ }
+ now = time(NULL);
+#ifdef NNG_HAVE_LOCALTIME_R
+ struct tm tm;
+ // No timezone offset, not strictly ISO8601 compliant
+ strftime(when, sizeof(when), "%Y-%m-%d %T", localtime_r(&now, &tm));
+#else
+ strftime(when, sizeof(when), "%Y-%m-%d %T", localtime(&now));
+#endif
+
+ switch (level) {
+ case NNG_LOG_ERR:
+ sgr = "\x1b[31m"; // red
+ sgr0 = "\x1b[0m";
+ level_str = "ERROR";
+ break;
+ case NNG_LOG_WARN:
+ sgr = "\x1b[33m"; // yellow
+ sgr0 = "\x1b[0m";
+ level_str = "WARN";
+ break;
+ case NNG_LOG_NOTICE:
+ sgr = "\x1b[1m"; // bold
+ sgr0 = "\x1b[0m";
+ level_str = "NOTICE";
+ break;
+ case NNG_LOG_DEBUG:
+ sgr = "\x1b[36m"; // cyan
+ sgr0 = "\x1b[0m";
+ level_str = "DEBUG";
+ break;
+ case NNG_LOG_INFO:
+ sgr = "";
+ sgr0 = "";
+ level_str = "INFO";
+ break;
+ default:
+ sgr = "";
+ sgr0 = "";
+ level_str = "NONE";
+ break;
+ }
+
+ if (!colors) {
+ sgr = "";
+ sgr0 = "";
+ }
+
+ (void) fprintf(stderr, "%s[%-6s]: %s: %s%s%s%s\n", sgr, level_str,
+ when, msgid ? msgid : "", msgid ? ": " : "", msg, sgr0);
+}
+
+void
+nng_system_logger(nng_log_level level, nng_log_facility facility,
+ const char *msgid, const char *msg)
+{
+#ifdef NNG_PLATFORM_POSIX
+ int pri;
+ switch (level) {
+ case NNG_LOG_ERR:
+ pri = LOG_ERR;
+ break;
+ case NNG_LOG_WARN:
+ pri = LOG_WARNING;
+ break;
+ case NNG_LOG_NOTICE:
+ pri = LOG_NOTICE;
+ break;
+ case NNG_LOG_INFO:
+ pri = LOG_INFO;
+ break;
+ case NNG_LOG_DEBUG:
+ pri = LOG_DEBUG;
+ break;
+ default:
+ pri = LOG_INFO;
+ break;
+ }
+ switch (facility) {
+ case NNG_LOG_DAEMON:
+ pri |= LOG_DAEMON;
+ break;
+ case NNG_LOG_USER:
+ pri |= LOG_USER;
+ break;
+ case NNG_LOG_AUTH:
+ pri |= LOG_AUTHPRIV;
+ break;
+ case NNG_LOG_LOCAL0:
+ pri |= LOG_LOCAL0;
+ break;
+ case NNG_LOG_LOCAL1:
+ pri |= LOG_LOCAL1;
+ break;
+ case NNG_LOG_LOCAL2:
+ pri |= LOG_LOCAL2;
+ break;
+ case NNG_LOG_LOCAL3:
+ pri |= LOG_LOCAL3;
+ break;
+ case NNG_LOG_LOCAL4:
+ pri |= LOG_LOCAL4;
+ break;
+ case NNG_LOG_LOCAL5:
+ pri |= LOG_LOCAL5;
+ break;
+ case NNG_LOG_LOCAL6:
+ pri |= LOG_LOCAL6;
+ break;
+ case NNG_LOG_LOCAL7:
+ pri |= LOG_LOCAL7;
+ break;
+ }
+
+ if (msgid) {
+ syslog(pri, "%s: %s", msgid, msg);
+ } else {
+ syslog(pri, "%s", msg);
+ }
+#else
+ // everyone else just goes to stderr for now
+ nng_stderr_logger(level, facility, msgid, msg);
+#endif
+}
+
+static void
+nni_vlog(nng_log_level level, nng_log_facility facility, const char *msgid,
+ const char *msg, va_list ap)
+{
+ // nobody allowed to log at LOG_EMERG or using LOG_KERN
+ if (level > log_level || log_level == 0 || facility == 0) {
+ return;
+ }
+ char formatted[512];
+ vsnprintf(formatted, sizeof(formatted), msg, ap);
+ log_logger(level, facility, msgid, formatted);
+}
+
+void
+nng_log_debug(const char *msgid, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ nni_vlog(NNG_LOG_DEBUG, log_facility, msgid, msg, ap);
+ va_end(ap);
+}
+
+void
+nng_log_info(const char *msgid, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ nni_vlog(NNG_LOG_INFO, log_facility, msgid, msg, ap);
+ va_end(ap);
+}
+
+void
+nng_log_notice(const char *msgid, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ nni_vlog(NNG_LOG_NOTICE, log_facility, msgid, msg, ap);
+ va_end(ap);
+}
+
+void
+nng_log_warn(const char *msgid, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ nni_vlog(NNG_LOG_WARN, log_facility, msgid, msg, ap);
+ va_end(ap);
+}
+
+void
+nng_log_err(const char *msgid, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ nni_vlog(NNG_LOG_ERR, log_facility, msgid, msg, ap);
+ va_end(ap);
+}
+
+void
+nng_log_auth(nng_log_level level, const char *msgid, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ nni_vlog(level, NNG_LOG_AUTH, msgid, msg, ap);
+ va_end(ap);
+}