mosquitto/src/logging.c

392 lines
8.8 KiB
C
Raw Normal View History

2014-05-07 22:27:00 +00:00
/*
Copyright (c) 2009-2020 Roger Light <roger@atchoo.org>
2014-05-07 22:27:00 +00:00
All rights reserved. This program and the accompanying materials
2020-11-25 17:34:21 +00:00
are made available under the terms of the Eclipse Public License 2.0
2014-05-07 22:27:00 +00:00
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
2020-11-25 17:34:21 +00:00
https://www.eclipse.org/legal/epl-2.0/
2014-05-07 22:27:00 +00:00
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
2020-12-01 18:21:59 +00:00
2014-05-07 22:27:00 +00:00
Contributors:
Roger Light - initial implementation and documentation.
*/
#include "config.h"
2014-05-07 22:27:00 +00:00
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifndef WIN32
#include <syslog.h>
#endif
2014-06-02 00:01:29 +00:00
#include <time.h>
2014-05-07 22:27:00 +00:00
#if defined(__APPLE__)
# include <sys/time.h>
#endif
#ifdef WITH_DLT
#include <sys/stat.h>
#include <dlt/dlt.h>
#endif
#include "logging_mosq.h"
#include "mosquitto_broker_internal.h"
2015-04-29 20:37:47 +00:00
#include "memory_mosq.h"
#include "misc_mosq.h"
2015-04-29 20:37:47 +00:00
#include "util_mosq.h"
2014-05-07 22:27:00 +00:00
#ifdef WIN32
HANDLE syslog_h;
#endif
static char log_fptr_buffer[BUFSIZ];
2014-05-07 22:27:00 +00:00
/* Options for logging should be:
*
* A combination of:
* Via syslog
* To a file
* To stdout/stderr
* To topics
*/
/* Give option of logging timestamp.
* Logging pid.
*/
2020-10-17 00:23:08 +00:00
static unsigned int log_destinations = MQTT3_LOG_STDERR;
static unsigned int log_priorities = MOSQ_LOG_ERR | MOSQ_LOG_WARNING | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO;
2014-05-07 22:27:00 +00:00
#ifdef WITH_DLT
static DltContext dltContext;
static bool dlt_allowed = false;
void dlt_fifo_check(void)
{
struct stat statbuf;
int fd;
/* If we start DLT but the /tmp/dlt fifo doesn't exist, or isn't available
* for writing then there is a big delay when we try and close the log
* later, so check for it first. This has the side effect of not letting
* people using DLT create the fifo after Mosquitto has started, but at the
* benefit of not having a massive delay for everybody else. */
memset(&statbuf, 0, sizeof(statbuf));
if(stat("/tmp/dlt", &statbuf) == 0){
if(S_ISFIFO(statbuf.st_mode)){
fd = open("/tmp/dlt", O_NONBLOCK | O_WRONLY);
if(fd != -1){
dlt_allowed = true;
close(fd);
}
}
}
}
#endif
static int get_time(struct tm **ti)
{
time_t s;
2020-11-06 17:16:35 +00:00
s = db.now_real_s;
*ti = localtime(&s);
if(!(*ti)){
fprintf(stderr, "Error obtaining system time.\n");
return 1;
}
return 0;
}
2015-05-16 18:03:12 +00:00
int log__init(struct mosquitto__config *config)
2014-05-07 22:27:00 +00:00
{
int rc = 0;
2015-02-05 22:44:38 +00:00
log_priorities = config->log_type;
log_destinations = config->log_dest;
2014-05-07 22:27:00 +00:00
if(log_destinations & MQTT3_LOG_SYSLOG){
#ifndef WIN32
2015-02-05 22:44:38 +00:00
openlog("mosquitto", LOG_PID|LOG_CONS, config->log_facility);
2014-05-07 22:27:00 +00:00
#else
syslog_h = OpenEventLog(NULL, "mosquitto");
#endif
}
2015-02-05 22:44:38 +00:00
if(log_destinations & MQTT3_LOG_FILE){
2017-07-16 21:52:01 +00:00
config->log_fptr = mosquitto__fopen(config->log_file, "at", true);
2020-07-19 20:59:28 +00:00
if(config->log_fptr){
setvbuf(config->log_fptr, log_fptr_buffer, _IOLBF, sizeof(log_fptr_buffer));
2020-07-19 20:59:28 +00:00
}else{
log_destinations = MQTT3_LOG_STDERR;
log_priorities = MOSQ_LOG_ERR;
2015-05-18 07:53:21 +00:00
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open log file %s for writing.", config->log_file);
2015-02-05 22:44:38 +00:00
}
}
#ifdef WITH_DLT
dlt_fifo_check();
if(dlt_allowed){
DLT_REGISTER_APP("MQTT","mosquitto log");
dlt_register_context(&dltContext, "MQTT", "mosquitto DLT context");
}
#endif
2014-05-07 22:27:00 +00:00
return rc;
}
2015-05-16 18:03:12 +00:00
int log__close(struct mosquitto__config *config)
2014-05-07 22:27:00 +00:00
{
if(log_destinations & MQTT3_LOG_SYSLOG){
#ifndef WIN32
closelog();
#else
CloseEventLog(syslog_h);
#endif
}
2015-02-05 22:44:38 +00:00
if(log_destinations & MQTT3_LOG_FILE){
if(config->log_fptr){
fclose(config->log_fptr);
config->log_fptr = NULL;
2015-02-05 22:44:38 +00:00
}
}
2014-05-07 22:27:00 +00:00
#ifdef WITH_DLT
if(dlt_allowed){
dlt_unregister_context(&dltContext);
DLT_UNREGISTER_APP();
}
#endif
2015-02-05 22:44:38 +00:00
/* FIXME - do something for all destinations! */
2014-05-07 22:27:00 +00:00
return MOSQ_ERR_SUCCESS;
}
#ifdef WITH_DLT
2020-10-17 00:23:08 +00:00
DltLogLevelType get_dlt_level(unsigned int priority)
{
switch (priority) {
case MOSQ_LOG_ERR:
return DLT_LOG_ERROR;
case MOSQ_LOG_WARNING:
return DLT_LOG_WARN;
case MOSQ_LOG_INFO:
return DLT_LOG_INFO;
case MOSQ_LOG_DEBUG:
return DLT_LOG_DEBUG;
case MOSQ_LOG_NOTICE:
case MOSQ_LOG_SUBSCRIBE:
case MOSQ_LOG_UNSUBSCRIBE:
return DLT_LOG_VERBOSE;
default:
return DLT_LOG_DEFAULT;
}
}
#endif
2021-03-21 09:17:53 +00:00
static int log__vprintf(unsigned int priority, const char *fmt, va_list va)
2014-05-07 22:27:00 +00:00
{
const char *topic;
int syslog_priority;
2020-10-27 17:13:28 +00:00
char log_line[1000];
size_t log_line_pos;
2020-10-27 17:13:28 +00:00
#ifdef WIN32
char *sp;
#endif
bool log_timestamp = true;
char *log_timestamp_format = NULL;
FILE *log_fptr = NULL;
if(db.config){
log_timestamp = db.config->log_timestamp;
log_timestamp_format = db.config->log_timestamp_format;
log_fptr = db.config->log_fptr;
}
2014-05-07 22:27:00 +00:00
if((log_priorities & priority) && log_destinations != MQTT3_LOG_NONE){
switch(priority){
case MOSQ_LOG_SUBSCRIBE:
topic = "$SYS/broker/log/M/subscribe";
#ifndef WIN32
syslog_priority = LOG_NOTICE;
#else
syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
break;
case MOSQ_LOG_UNSUBSCRIBE:
topic = "$SYS/broker/log/M/unsubscribe";
#ifndef WIN32
syslog_priority = LOG_NOTICE;
#else
syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
break;
case MOSQ_LOG_DEBUG:
topic = "$SYS/broker/log/D";
#ifndef WIN32
syslog_priority = LOG_DEBUG;
#else
syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
break;
case MOSQ_LOG_ERR:
topic = "$SYS/broker/log/E";
#ifndef WIN32
syslog_priority = LOG_ERR;
#else
syslog_priority = EVENTLOG_ERROR_TYPE;
#endif
break;
case MOSQ_LOG_WARNING:
topic = "$SYS/broker/log/W";
#ifndef WIN32
syslog_priority = LOG_WARNING;
#else
syslog_priority = EVENTLOG_WARNING_TYPE;
#endif
break;
case MOSQ_LOG_NOTICE:
topic = "$SYS/broker/log/N";
#ifndef WIN32
syslog_priority = LOG_NOTICE;
#else
syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
break;
case MOSQ_LOG_INFO:
topic = "$SYS/broker/log/I";
#ifndef WIN32
syslog_priority = LOG_INFO;
#else
syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
break;
2015-02-13 22:57:49 +00:00
#ifdef WITH_WEBSOCKETS
case MOSQ_LOG_WEBSOCKETS:
topic = "$SYS/broker/log/WS";
#ifndef WIN32
syslog_priority = LOG_DEBUG;
#else
syslog_priority = EVENTLOG_INFORMATION_TYPE;
#endif
break;
#endif
2014-05-07 22:27:00 +00:00
default:
topic = "$SYS/broker/log/E";
#ifndef WIN32
syslog_priority = LOG_ERR;
#else
syslog_priority = EVENTLOG_ERROR_TYPE;
#endif
}
2020-10-27 17:13:28 +00:00
if(log_timestamp){
if(log_timestamp_format){
struct tm *ti = NULL;
get_time(&ti);
log_line_pos = strftime(log_line, sizeof(log_line), log_timestamp_format, ti);
if(log_line_pos == 0){
log_line_pos = (size_t)snprintf(log_line, sizeof(log_line), "Time error");
}
2014-05-07 22:27:00 +00:00
}else{
2020-11-06 17:16:35 +00:00
log_line_pos = (size_t)snprintf(log_line, sizeof(log_line), "%d", (int)db.now_real_s);
2014-05-07 22:27:00 +00:00
}
2020-10-27 17:13:28 +00:00
if(log_line_pos < sizeof(log_line)-3){
log_line[log_line_pos] = ':';
log_line[log_line_pos+1] = ' ';
log_line[log_line_pos+2] = '\0';
log_line_pos += 2;
}
}else{
log_line_pos = 0;
}
vsnprintf(&log_line[log_line_pos], sizeof(log_line)-log_line_pos, fmt, va);
log_line[sizeof(log_line)-1] = '\0'; /* Ensure string is null terminated. */
if(log_destinations & MQTT3_LOG_STDOUT){
fprintf(stdout, "%s\n", log_line);
2014-05-07 22:27:00 +00:00
}
if(log_destinations & MQTT3_LOG_STDERR){
2020-10-27 17:13:28 +00:00
fprintf(stderr, "%s\n", log_line);
2014-05-07 22:27:00 +00:00
}
if(log_destinations & MQTT3_LOG_FILE && log_fptr){
2020-10-27 17:13:28 +00:00
fprintf(log_fptr, "%s\n", log_line);
#ifdef WIN32
/* Windows doesn't support line buffering, so flush. */
fflush(log_fptr);
#endif
2014-05-07 22:27:00 +00:00
}
if(log_destinations & MQTT3_LOG_SYSLOG){
#ifndef WIN32
2020-10-27 17:13:28 +00:00
syslog(syslog_priority, "%s", log_line);
2014-05-07 22:27:00 +00:00
#else
2020-10-27 17:13:28 +00:00
sp = (char *)log_line;
2014-05-07 22:27:00 +00:00
ReportEvent(syslog_h, syslog_priority, 0, 0, NULL, 1, 0, &sp, NULL);
#endif
}
if(log_destinations & MQTT3_LOG_TOPIC && priority != MOSQ_LOG_DEBUG && priority != MOSQ_LOG_INTERNAL){
db__messages_easy_queue(NULL, topic, 2, (uint32_t)strlen(log_line), log_line, 0, 20, NULL);
2014-05-07 22:27:00 +00:00
}
#ifdef WITH_DLT
if(log_destinations & MQTT3_LOG_DLT && priority != MOSQ_LOG_INTERNAL){
2020-10-27 17:13:28 +00:00
DLT_LOG_STRING(dltContext, get_dlt_level(priority), log_line);
}
#endif
2014-05-07 22:27:00 +00:00
}
return MOSQ_ERR_SUCCESS;
}
2020-10-17 00:23:08 +00:00
int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt, ...)
{
va_list va;
int rc;
2019-03-13 14:11:50 +00:00
UNUSED(mosq);
va_start(va, fmt);
2015-05-18 07:53:21 +00:00
rc = log__vprintf(priority, fmt, va);
va_end(va);
return rc;
}
void log__internal(const char *fmt, ...)
{
va_list va;
2019-05-28 21:00:11 +00:00
char buf[200];
int len;
va_start(va, fmt);
2019-05-28 21:00:11 +00:00
len = vsnprintf(buf, 200, fmt, va);
va_end(va);
2019-05-28 21:00:11 +00:00
if(len >= 200){
log__printf(NULL, MOSQ_LOG_INTERNAL, "Internal log buffer too short (%d)", len);
return;
}
2020-12-02 19:41:46 +00:00
#ifdef WIN32
log__printf(NULL, MOSQ_LOG_INTERNAL, "%s", buf);
#else
2020-01-29 16:25:56 +00:00
log__printf(NULL, MOSQ_LOG_INTERNAL, "%s%s%s", "\e[32m", buf, "\e[0m");
2020-12-02 19:41:46 +00:00
#endif
}
2015-05-18 07:53:21 +00:00
int mosquitto_log_vprintf(int level, const char *fmt, va_list va)
{
2020-10-17 00:23:08 +00:00
return log__vprintf((unsigned int)level, fmt, va);
2015-05-18 07:53:21 +00:00
}
void mosquitto_log_printf(int level, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
2020-10-17 00:23:08 +00:00
log__vprintf((unsigned int)level, fmt, va);
va_end(va);
}