summaryrefslogtreecommitdiff
path: root/debug.cpp
blob: 7bff2a81c2bb479fe851bc31e7ccacac4f0dca2b (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
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright 2013 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the GNU General Public License, version 2 or any
 * later version. See the file COPYING in the top-level directory of
 * this distribution or http://www.gnu.org/licenses/gpl-2.0.txt.
 */
#include "stdafx.h"

#define SPICEX_DEBUG_LEVEL "SPICEX_DEBUG_LEVEL"

static FILE *log_file = NULL;
static unsigned int log_level = LOG_DEBUG;

void spicex_log_cleanup(void)
{
    if (log_file) {
        LOG_INFO("done");
        fclose(log_file);
        log_file = NULL;
    }
}

template<class T>
class AutoArray {
public:
    AutoArray() : _array (NULL) {}
    AutoArray(T* array) : _array (array) {}
    ~AutoArray() { delete[] _array;}

    void set(T* array) { delete[] _array; _array = array;}
    T* get() {return _array;}
    T* release() {T* tmp = _array; _array = NULL; return tmp; }
    T& operator [] (int i) {return _array[i];}

private:
    T* _array;
};

void string_vprintf(std::string& str, const char* format, va_list ap)
{
    int buf_size = 256;
    for (;;) {
        AutoArray<char> buf(new char[buf_size]);
        int r = vsnprintf_s(buf.get(), buf_size, buf_size - 1, format, ap);
        if (r != -1) {
            str = buf.get();
            return;
        }
        buf_size *= 2;
    }
}

const char *type_to_str(int type)
{
    switch (type) {
        case LOG_INFO: return "INFO";
        case LOG_WARN: return "WARN";
        case LOG_ERROR: return "ERROR";
        case LOG_FATAL: return "FATAL";
    }
    if (type >= LOG_DEBUG) {
        return "DEBUG";
    }
    return "UNKNOWN";
}


void spicex_log(unsigned int type, const char *function, const char *format, ...)
{
    std::string formated_message;
    va_list ap;
    std::string function_name_copy = std::string(function);

    if (type > log_level) {
      return;
    }

    ASSERT(type <= LOG_FATAL);

    va_start(ap, format);
    string_vprintf(formated_message, format, ap);
    va_end(ap);

    if (type <= log_level && log_file != NULL) {
        fprintf(log_file, "%ld %s [%lu:%lu] %s: %s\n", (long)time(NULL), type_to_str(type),
                GetCurrentProcessId(), GetCurrentThreadId(),
                function_name_copy.c_str(), formated_message.c_str());
        fflush(log_file);
    }
}

char *safe_getenv(const char *name)
{
    char *value;
    size_t number_of_elements;

    _dupenv_s(&value, &number_of_elements, name);
    return value;
}

void spicex_init_logger(void)
{
    std::string log_file_name;
    char *p;
    long int env_log_level;
    char *temp = safe_getenv("TEMP");
    char *log_level_str = safe_getenv(SPICEX_DEBUG_LEVEL);

    log_level = LOG_INFO;
    // VVV Windows specific, assumes %TEMP% is defined.
    log_file_name = std::string(temp) + "\\spicex.log";

    log_file = _fsopen(log_file_name.c_str(), "a", _SH_DENYNO);
    if (log_file == NULL) {
        fprintf(stderr, "Failed to open log file %s\n", log_file_name.c_str());
        goto cleanup;
    }

    if (log_level_str == NULL) {
        goto cleanup;
    }

    env_log_level = strtol(log_level_str, &p, 10);
    if (p - log_level_str == 0) {
        LOG_INFO("%s environment variable doesn't contain a number", SPICEX_DEBUG_LEVEL);
    } else {
        log_level = LOG_DEBUG + env_log_level;
    }

cleanup:
    free(temp);
    free(log_level_str);
    if (log_file != NULL) {
        LOG_INFO("started");
    }
}