log.c 4.38 KB
Newer Older
Jack Moffitt's avatar
Jack Moffitt committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>

#ifndef _WIN32
#include <pthread.h>
#else
#include <windows.h>
#endif

#include "log.h"

#define LOG_MAXLOGS 25
#define LOG_MAXLINELEN 1024

#ifdef _WIN32
#define mutex_t CRITICAL_SECTION
20 21
#define snprintf _snprintf
#define vsnprintf _vsnprintf
Jack Moffitt's avatar
Jack Moffitt committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
#else
#define mutex_t pthread_mutex_t
#endif

static mutex_t _logger_mutex;
static int _initialized = 0;

typedef struct log_tag
{
	int in_use;

	int level;

	char *filename;
	FILE *logfile;
	
Michael Smith's avatar
Michael Smith committed
38
    char *buffer;
Jack Moffitt's avatar
Jack Moffitt committed
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
} log_t;

log_t loglist[LOG_MAXLOGS];

int _get_log_id();
void _release_log_id(int log_id);
static void _lock_logger();
static void _unlock_logger();

void log_initialize()
{
	int i;

	if (_initialized) return;

	for (i = 0; i < LOG_MAXLOGS; i++) {
		loglist[i].in_use = 0;
		loglist[i].level = 2;
		loglist[i].filename = NULL;
		loglist[i].logfile = NULL;
		loglist[i].buffer = NULL;
	}

	/* initialize mutexes */
#ifndef _WIN32
	pthread_mutex_init(&_logger_mutex, NULL);
#else
	InitializeCriticalSection(&_logger_mutex);
#endif

	_initialized = 1;
}

72
int log_open_file(FILE *file)
Jack Moffitt's avatar
Jack Moffitt committed
73
{
74
    int log_id;
Jack Moffitt's avatar
Jack Moffitt committed
75

76
    if(file == NULL) return LOG_EINSANE;
Jack Moffitt's avatar
Jack Moffitt committed
77 78 79 80

	log_id = _get_log_id();
	if (log_id < 0) return LOG_ENOMORELOGS;

81
	loglist[log_id].logfile = file;
Jack Moffitt's avatar
Jack Moffitt committed
82
	if (loglist[log_id].logfile != NULL) {
83
		loglist[log_id].filename = NULL;
Jack Moffitt's avatar
Jack Moffitt committed
84 85 86 87
	} else {
		_release_log_id(log_id);
		return LOG_ECANTOPEN;
	}
88

Jack Moffitt's avatar
Jack Moffitt committed
89 90 91
	return log_id;
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

int log_open(const char *filename)
{
	int ret;
    FILE *file;

	if (filename == NULL) return LOG_EINSANE;
	if (strcmp(filename, "") == 0) return LOG_EINSANE;
    
    file = fopen(filename, "a");

    ret = log_open_file(file);

	if(ret >= 0)
        setvbuf(file, NULL, _IOLBF, 0);

    return ret;
}

Jack Moffitt's avatar
Jack Moffitt committed
111 112 113
int log_open_with_buffer(const char *filename, int size)
{
	/* not implemented */
Jack Moffitt's avatar
Jack Moffitt committed
114
	return LOG_ENOTIMPL;
Jack Moffitt's avatar
Jack Moffitt committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
}

void log_set_level(int log_id, int level)
{
	if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
	if (loglist[log_id].in_use == 0) return;

	loglist[log_id].level = level;
}

void log_flush(int log_id)
{
	if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
	if (loglist[log_id].in_use == 0) return;

	fflush(loglist[log_id].logfile);
}

void log_reopen(int log_id)
{
	/* not implemented yet */
}

void log_close(int log_id)
{
	if (log_id < 0 || log_id >= LOG_MAXLOGS) return;
	if (loglist[log_id].in_use == 0) return;

	loglist[log_id].in_use = 0;
	loglist[log_id].level = 2;
	if (loglist[log_id].filename) free(loglist[log_id].filename);
	if (loglist[log_id].buffer) free(loglist[log_id].buffer);
	fclose(loglist[log_id].logfile);
	loglist[log_id].logfile = NULL;
}

void log_shutdown()
{
	/* destroy mutexes */
#ifndef _WIN32
	pthread_mutex_destroy(&_logger_mutex);
#else
	DeleteCriticalSection(&_logger_mutex);
#endif 

	_initialized = 0;
}

void log_write(int log_id, int priority, const char *cat, const char *fmt, ...)
{
        static char prior[4][5] = { "EROR\0", "WARN\0", "INFO\0", "DBUG\0" };
	char tyme[128];
	char pre[256];
	char line[LOG_MAXLINELEN];
	time_t now;
	va_list ap;

	if (log_id < 0) return;
Michael Smith's avatar
Michael Smith committed
173
    if (log_id > LOG_MAXLOGS) return; /* Bad log number */
Jack Moffitt's avatar
Jack Moffitt committed
174
	if (loglist[log_id].level < priority) return;
Michael Smith's avatar
Michael Smith committed
175
    if (priority > 4) return; /* Bad priority */
Jack Moffitt's avatar
Jack Moffitt committed
176 177 178 179 180 181


	va_start(ap, fmt);
	vsnprintf(line, LOG_MAXLINELEN, fmt, ap);

	now = time(NULL);
182
	strftime(tyme, 128, "[%Y-%m-%d  %H:%M:%S]", localtime(&now)); 
Jack Moffitt's avatar
Jack Moffitt committed
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

	snprintf(pre, 256, "%s %s", prior[priority-1], cat);

	fprintf(loglist[log_id].logfile, "%s %s %s\n", tyme, pre, line); 

	va_end(ap);
}

void log_write_direct(int log_id, const char *fmt, ...)
{
	char line[LOG_MAXLINELEN];
	va_list ap;

	if (log_id < 0) return;
	
	va_start(ap, fmt);
	vsnprintf(line, LOG_MAXLINELEN, fmt, ap);
	fprintf(loglist[log_id].logfile, "%s\n", line);
	va_end(ap);

	fflush(loglist[log_id].logfile);
}

int _get_log_id()
{
	int i;
	int id = -1;

	/* lock mutex */
	_lock_logger();

	for (i = 0; i < LOG_MAXLOGS; i++)
		if (loglist[i].in_use == 0) {
			loglist[i].in_use = 1;
			id = i;
			break;
		}

	/* unlock mutex */
	_unlock_logger();

	return id;
}

void _release_log_id(int log_id)
{
	/* lock mutex */
	_lock_logger();

	loglist[log_id].in_use = 0;

	/* unlock mutex */
	_unlock_logger();
}

static void _lock_logger()
{
#ifndef _WIN32
	pthread_mutex_lock(&_logger_mutex);
#else
	EnterCriticalSection(&_logger_mutex);
#endif
}

static void _unlock_logger()
{
#ifndef _WIN32
	pthread_mutex_unlock(&_logger_mutex);
#else
	LeaveCriticalSection(&_logger_mutex);
#endif	
}