summaryrefslogtreecommitdiffstats
path: root/mqtt_websockets/src/mqtt_wss_log.c
blob: 2c8cf32e588f57d1715c2441865b8a55adf32b3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "mqtt_wss_log.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "common_internal.h"

struct mqtt_wss_log_ctx {
    mqtt_wss_log_callback_t extern_log_fnc;
    char *ctx_prefix;
    char *buffer;
    char *buffer_w_ptr;
    size_t buffer_bytes_avail;
};

#define LOG_BUFFER_SIZE 1024 * 4
#define LOG_CTX_PREFIX_SEV_STR "  : "
#define LOG_CTX_PREFIX_LIMIT 15
#define LOG_CTX_PREFIX_LIMIT_STR (LOG_CTX_PREFIX_LIMIT - (2 + strlen(LOG_CTX_PREFIX_SEV_STR)))  // with [] characters and affixed ' ' it is total 15 chars
#if (LOG_CTX_PREFIX_LIMIT * 10) > LOG_BUFFER_SIZE
#error "LOG_BUFFER_SIZE too small"
#endif
mqtt_wss_log_ctx_t mqtt_wss_log_ctx_create(const char *ctx_prefix, mqtt_wss_log_callback_t log_callback)
{
    mqtt_wss_log_ctx_t ctx = mw_calloc(1, sizeof(struct mqtt_wss_log_ctx));
    if(!ctx)
        return NULL;

    if(log_callback) {
        ctx->extern_log_fnc = log_callback;
        ctx->buffer = mw_calloc(1, LOG_BUFFER_SIZE);
        if(!ctx->buffer)
            goto cleanup;

        ctx->buffer_w_ptr = ctx->buffer;
        if(ctx_prefix) {
            *(ctx->buffer_w_ptr++) = '[';
            strncpy(ctx->buffer_w_ptr, ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
            ctx->buffer_w_ptr += strnlen(ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
            *(ctx->buffer_w_ptr++) = ']';
        }
        strcpy(ctx->buffer_w_ptr, LOG_CTX_PREFIX_SEV_STR);
        ctx->buffer_w_ptr += strlen(LOG_CTX_PREFIX_SEV_STR);
        // no term '\0' -> calloc is used

        ctx->buffer_bytes_avail = LOG_BUFFER_SIZE - strlen(ctx->buffer);

        return ctx;
    }

    if(ctx_prefix) {
        ctx->ctx_prefix = strndup(ctx_prefix, LOG_CTX_PREFIX_LIMIT_STR);
        if(!ctx->ctx_prefix)
            goto cleanup;
    }

    return ctx;

cleanup:
    mw_free(ctx);
    return NULL;
}

void mqtt_wss_log_ctx_destroy(mqtt_wss_log_ctx_t ctx)
{
    mw_free(ctx->ctx_prefix);
    mw_free(ctx->buffer);
    mw_free(ctx);
}

static inline char severity_to_c(int severity)
{
    switch (severity) {
        case MQTT_WSS_LOG_FATAL:
            return 'F';
        case MQTT_WSS_LOG_ERROR:
            return 'E';
        case MQTT_WSS_LOG_WARN:
            return 'W';
        case MQTT_WSS_LOG_INFO:
            return 'I';
        case MQTT_WSS_LOG_DEBUG:
            return 'D';
        default:
            return '?';
    }
}

void mws_log(int severity, mqtt_wss_log_ctx_t ctx, const char *fmt, va_list args)
{
    size_t size;

    if(ctx->extern_log_fnc) {
        size = vsnprintf(ctx->buffer_w_ptr, ctx->buffer_bytes_avail, fmt, args);
        *(ctx->buffer_w_ptr - 3) = severity_to_c(severity);

        ctx->extern_log_fnc(severity, ctx->buffer);

        if(size >= ctx->buffer_bytes_avail)
            mws_error(ctx, "Last message of this type was truncated! Consider what you log or increase LOG_BUFFER_SIZE if really needed.");

        return;
    }

    if(ctx->ctx_prefix)
        printf("[%s] ", ctx->ctx_prefix);

    printf("%c: ", severity_to_c(severity));

    vprintf(fmt, args);
    putchar('\n');
}

#define DEFINE_MWS_SEV_FNC(severity_fncname, severity) \
void mws_ ## severity_fncname(mqtt_wss_log_ctx_t ctx, const char *fmt, ...) \
{ \
    va_list args; \
    va_start(args, fmt); \
    mws_log(severity, ctx, fmt, args); \
    va_end(args); \
}

DEFINE_MWS_SEV_FNC(fatal, MQTT_WSS_LOG_FATAL)
DEFINE_MWS_SEV_FNC(error, MQTT_WSS_LOG_ERROR)
DEFINE_MWS_SEV_FNC(warn,  MQTT_WSS_LOG_WARN )
DEFINE_MWS_SEV_FNC(info,  MQTT_WSS_LOG_INFO )
DEFINE_MWS_SEV_FNC(debug, MQTT_WSS_LOG_DEBUG)