| 1 |
/* |
|---|
| 2 |
* Copyright (c) 2007, OmniTI Computer Consulting, Inc. |
|---|
| 3 |
* All rights reserved. |
|---|
| 4 |
*/ |
|---|
| 5 |
|
|---|
| 6 |
#include "noit_defines.h" |
|---|
| 7 |
#include <stdio.h> |
|---|
| 8 |
#include <fcntl.h> |
|---|
| 9 |
#include <unistd.h> |
|---|
| 10 |
|
|---|
| 11 |
#include "utils/noit_log.h" |
|---|
| 12 |
#include "utils/noit_hash.h" |
|---|
| 13 |
|
|---|
| 14 |
static noit_hash_table noit_loggers = NOIT_HASH_EMPTY; |
|---|
| 15 |
noit_log_stream_t noit_stderr = NULL; |
|---|
| 16 |
noit_log_stream_t noit_error = NULL; |
|---|
| 17 |
noit_log_stream_t noit_debug = NULL; |
|---|
| 18 |
|
|---|
| 19 |
static int |
|---|
| 20 |
posix_logio_open(noit_log_stream_t ls) { |
|---|
| 21 |
int fd; |
|---|
| 22 |
fd = open(ls->path, O_CREAT|O_WRONLY|O_APPEND); |
|---|
| 23 |
if(fd < 0) { |
|---|
| 24 |
ls->op_ctx = NULL; |
|---|
| 25 |
return -1; |
|---|
| 26 |
} |
|---|
| 27 |
ls->op_ctx = (void *)fd; |
|---|
| 28 |
return 0; |
|---|
| 29 |
} |
|---|
| 30 |
static int |
|---|
| 31 |
posix_logio_reopen(noit_log_stream_t ls) { |
|---|
| 32 |
if(ls->path) { |
|---|
| 33 |
int newfd, oldfd; |
|---|
| 34 |
oldfd = (int)ls->op_ctx; |
|---|
| 35 |
newfd = open(ls->path, O_CREAT|O_WRONLY|O_APPEND); |
|---|
| 36 |
if(newfd >= 0) { |
|---|
| 37 |
ls->op_ctx = (void *)newfd; |
|---|
| 38 |
if(oldfd >= 0) close(oldfd); |
|---|
| 39 |
return 0; |
|---|
| 40 |
} |
|---|
| 41 |
} |
|---|
| 42 |
return -1; |
|---|
| 43 |
} |
|---|
| 44 |
static int |
|---|
| 45 |
posix_logio_write(noit_log_stream_t ls, const void *buf, size_t len) { |
|---|
| 46 |
int fd; |
|---|
| 47 |
fd = (int)ls->op_ctx; |
|---|
| 48 |
if(fd < 0) return -1; |
|---|
| 49 |
return write(fd, buf, len); |
|---|
| 50 |
} |
|---|
| 51 |
static int |
|---|
| 52 |
posix_logio_close(noit_log_stream_t ls) { |
|---|
| 53 |
int fd; |
|---|
| 54 |
fd = (int)ls->op_ctx; |
|---|
| 55 |
return close(fd); |
|---|
| 56 |
} |
|---|
| 57 |
static logops_t posix_logio_ops = { |
|---|
| 58 |
posix_logio_open, |
|---|
| 59 |
posix_logio_reopen, |
|---|
| 60 |
posix_logio_write, |
|---|
| 61 |
posix_logio_close, |
|---|
| 62 |
}; |
|---|
| 63 |
|
|---|
| 64 |
void |
|---|
| 65 |
noit_log_init() { |
|---|
| 66 |
noit_hash_init(&noit_loggers); |
|---|
| 67 |
noit_stderr = noit_log_stream_new_on_fd("stderr", 2); |
|---|
| 68 |
noit_error = noit_log_stream_new("error", NULL); |
|---|
| 69 |
noit_debug = noit_log_stream_new("debug", NULL); |
|---|
| 70 |
} |
|---|
| 71 |
|
|---|
| 72 |
noit_log_stream_t |
|---|
| 73 |
noit_log_stream_new_on_fd(const char *name, int fd) { |
|---|
| 74 |
noit_log_stream_t ls; |
|---|
| 75 |
ls = calloc(1, sizeof(*ls)); |
|---|
| 76 |
ls->name = strdup(name); |
|---|
| 77 |
ls->ops = &posix_logio_ops; |
|---|
| 78 |
ls->op_ctx = (void *)fd; |
|---|
| 79 |
ls->enabled = 1; |
|---|
| 80 |
if(noit_hash_store(&noit_loggers, ls->name, strlen(ls->name), ls) == 0) { |
|---|
| 81 |
free(ls->name); |
|---|
| 82 |
free(ls); |
|---|
| 83 |
return NULL; |
|---|
| 84 |
} |
|---|
| 85 |
return ls; |
|---|
| 86 |
} |
|---|
| 87 |
|
|---|
| 88 |
noit_log_stream_t |
|---|
| 89 |
noit_log_stream_new_on_file(const char *path) { |
|---|
| 90 |
noit_log_stream_t ls; |
|---|
| 91 |
ls = calloc(1, sizeof(*ls)); |
|---|
| 92 |
ls->path = strdup(path); |
|---|
| 93 |
ls->ops = &posix_logio_ops; |
|---|
| 94 |
if(ls->ops->openop(ls)) { |
|---|
| 95 |
free(ls->path); |
|---|
| 96 |
free(ls); |
|---|
| 97 |
return NULL; |
|---|
| 98 |
} |
|---|
| 99 |
ls->name = strdup(ls->path); |
|---|
| 100 |
ls->enabled = 1; |
|---|
| 101 |
if(noit_hash_store(&noit_loggers, ls->name, strlen(ls->name), ls) == 0) { |
|---|
| 102 |
free(ls->path); |
|---|
| 103 |
free(ls->name); |
|---|
| 104 |
free(ls); |
|---|
| 105 |
return NULL; |
|---|
| 106 |
} |
|---|
| 107 |
return ls; |
|---|
| 108 |
} |
|---|
| 109 |
|
|---|
| 110 |
noit_log_stream_t |
|---|
| 111 |
noit_log_stream_new(const char *name, logops_t *ops) { |
|---|
| 112 |
noit_log_stream_t ls; |
|---|
| 113 |
ls = calloc(1, sizeof(*ls)); |
|---|
| 114 |
ls->name = strdup(name); |
|---|
| 115 |
ls->enabled = 1; |
|---|
| 116 |
ls->ops = ops ? ops : &posix_logio_ops; |
|---|
| 117 |
if(!ops) ls->op_ctx = (void *)-1; |
|---|
| 118 |
if(noit_hash_store(&noit_loggers, ls->name, strlen(ls->name), ls) == 0) { |
|---|
| 119 |
free(ls->name); |
|---|
| 120 |
free(ls); |
|---|
| 121 |
return NULL; |
|---|
| 122 |
} |
|---|
| 123 |
return ls; |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
noit_log_stream_t |
|---|
| 127 |
noit_log_stream_find(const char *name) { |
|---|
| 128 |
noit_log_stream_t ls; |
|---|
| 129 |
if(noit_hash_retrieve(&noit_loggers, name, strlen(name), (void **)&ls)) { |
|---|
| 130 |
return ls; |
|---|
| 131 |
} |
|---|
| 132 |
return NULL; |
|---|
| 133 |
} |
|---|
| 134 |
|
|---|
| 135 |
void |
|---|
| 136 |
noit_log_stream_add_stream(noit_log_stream_t ls, noit_log_stream_t outlet) { |
|---|
| 137 |
struct _noit_log_stream_outlet_list *newnode; |
|---|
| 138 |
newnode = calloc(1, sizeof(*newnode)); |
|---|
| 139 |
newnode->outlet = outlet; |
|---|
| 140 |
newnode->next = ls->outlets; |
|---|
| 141 |
ls->outlets = newnode; |
|---|
| 142 |
} |
|---|
| 143 |
|
|---|
| 144 |
noit_log_stream_t |
|---|
| 145 |
noit_log_stream_remove_stream(noit_log_stream_t ls, const char *name) { |
|---|
| 146 |
noit_log_stream_t outlet; |
|---|
| 147 |
struct _noit_log_stream_outlet_list *node, *tmp; |
|---|
| 148 |
if(!ls->outlets) return NULL; |
|---|
| 149 |
if(!strcmp(ls->outlets->outlet->name, name)) { |
|---|
| 150 |
node = ls->outlets; |
|---|
| 151 |
ls->outlets = node->next; |
|---|
| 152 |
outlet = node->outlet; |
|---|
| 153 |
free(node); |
|---|
| 154 |
return outlet; |
|---|
| 155 |
} |
|---|
| 156 |
for(node = ls->outlets; node->next; node = node->next) { |
|---|
| 157 |
if(!strcmp(node->next->outlet->name, name)) { |
|---|
| 158 |
/* splice */ |
|---|
| 159 |
tmp = node->next; |
|---|
| 160 |
node->next = tmp->next; |
|---|
| 161 |
/* pluck */ |
|---|
| 162 |
outlet = tmp->outlet; |
|---|
| 163 |
/* shed */ |
|---|
| 164 |
free(tmp); |
|---|
| 165 |
/* return */ |
|---|
| 166 |
return outlet; |
|---|
| 167 |
} |
|---|
| 168 |
} |
|---|
| 169 |
return NULL; |
|---|
| 170 |
} |
|---|
| 171 |
|
|---|
| 172 |
void noit_log_stream_reopen(noit_log_stream_t ls) { |
|---|
| 173 |
struct _noit_log_stream_outlet_list *node; |
|---|
| 174 |
ls->ops->reopenop(ls); |
|---|
| 175 |
for(node = ls->outlets; node; node = node->next) { |
|---|
| 176 |
noit_log_stream_reopen(node->outlet); |
|---|
| 177 |
} |
|---|
| 178 |
} |
|---|
| 179 |
|
|---|
| 180 |
void |
|---|
| 181 |
noit_log_stream_close(noit_log_stream_t ls) { |
|---|
| 182 |
struct _noit_log_stream_outlet_list *node; |
|---|
| 183 |
ls->ops->closeop(ls); |
|---|
| 184 |
for(node = ls->outlets; node; node = node->next) { |
|---|
| 185 |
noit_log_stream_close(node->outlet); |
|---|
| 186 |
} |
|---|
| 187 |
} |
|---|
| 188 |
|
|---|
| 189 |
void |
|---|
| 190 |
noit_log_stream_free(noit_log_stream_t ls) { |
|---|
| 191 |
if(ls) { |
|---|
| 192 |
struct _noit_log_stream_outlet_list *node; |
|---|
| 193 |
if(ls->name) free(ls->name); |
|---|
| 194 |
if(ls->path) free(ls->path); |
|---|
| 195 |
while(ls->outlets) { |
|---|
| 196 |
node = ls->outlets->next; |
|---|
| 197 |
free(ls->outlets); |
|---|
| 198 |
ls->outlets = node; |
|---|
| 199 |
} |
|---|
| 200 |
free(ls); |
|---|
| 201 |
} |
|---|
| 202 |
} |
|---|
| 203 |
|
|---|
| 204 |
void |
|---|
| 205 |
noit_vlog(noit_log_stream_t ls, struct timeval *now, |
|---|
| 206 |
const char *file, int line, |
|---|
| 207 |
const char *format, va_list arg) { |
|---|
| 208 |
char buffer[4096]; |
|---|
| 209 |
struct _noit_log_stream_outlet_list *node; |
|---|
| 210 |
#ifdef va_copy |
|---|
| 211 |
va_list copy; |
|---|
| 212 |
#endif |
|---|
| 213 |
|
|---|
| 214 |
if(ls->enabled) { |
|---|
| 215 |
int len; |
|---|
| 216 |
#ifdef va_copy |
|---|
| 217 |
va_copy(copy, arg); |
|---|
| 218 |
len = vsnprintf(buffer, sizeof(buffer), format, copy); |
|---|
| 219 |
va_end(copy); |
|---|
| 220 |
#else |
|---|
| 221 |
len = vsnprintf(buffer, sizeof(buffer), format, arg); |
|---|
| 222 |
#endif |
|---|
| 223 |
ls->ops->writeop(ls, buffer, len); /* Not much one can do about errors */ |
|---|
| 224 |
|
|---|
| 225 |
for(node = ls->outlets; node; node = node->next) { |
|---|
| 226 |
#ifdef va_copy |
|---|
| 227 |
va_copy(copy, arg); |
|---|
| 228 |
noit_vlog(node->outlet, now, file, line, format, copy); |
|---|
| 229 |
va_end(copy); |
|---|
| 230 |
#else |
|---|
| 231 |
noit_vlog(node->outlet, now, file, line, format, arg); |
|---|
| 232 |
#endif |
|---|
| 233 |
} |
|---|
| 234 |
} |
|---|
| 235 |
} |
|---|
| 236 |
|
|---|
| 237 |
void |
|---|
| 238 |
noit_log(noit_log_stream_t ls, struct timeval *now, |
|---|
| 239 |
const char *file, int line, const char *format, ...) { |
|---|
| 240 |
va_list arg; |
|---|
| 241 |
va_start(arg, format); |
|---|
| 242 |
noit_vlog(ls, now, file, line, format, arg); |
|---|
| 243 |
va_end(arg); |
|---|
| 244 |
} |
|---|
| 245 |
|
|---|