log.c (2815B)
1 /* 2 * Copyright 2021-2023 Jacob R. Edwards 3 * 4 * ap -- audio player 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20 /* Taken from OpenBSD /usr/include/syslog.h */ 21 #ifndef LOG_MASK 22 #define LOG_MASK(pri) (1 << (pri)) /* mask for one priority */ 23 #endif 24 25 #ifndef LOG_UPTO 26 #define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) /* all priorities through pri */ 27 #endif 28 29 #include <sys/socket.h> 30 31 #include <errno.h> 32 #include <limits.h> 33 #include <poll.h> 34 #include <stdarg.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <time.h> 38 39 #include "aps.h" 40 #include "bug.h" 41 #include "log.h" 42 #include "util.h" 43 44 static struct { 45 char *s; 46 int i; 47 } levels[] = { 48 { "debug", DEBUG }, 49 { "info", INFO }, 50 { "warn", WARN }, 51 { "error", ERROR }, 52 { "fatal", FATAL }, 53 { "none", 0 } 54 }; 55 56 int 57 logstrlevel(char *s) 58 { 59 int i; 60 61 for (i = 0; i < LEN(levels); ++i) 62 if (strcmp(levels[i].s, s) == 0) 63 return levels[i].i; 64 return -1; 65 } 66 67 char * 68 loglevelstr(int level) 69 { 70 int i; 71 72 for (i = 0; i < LEN(levels); ++i) 73 if (levels[i].i == level) 74 return levels[i].s; 75 return NULL; 76 } 77 78 int 79 logmask(int level) 80 { 81 return LOG_UPTO(level); 82 } 83 84 void 85 newbuflen(int size, int *len, int newlen, char *msg) 86 { 87 if (newlen < 0) 88 bug(msg); 89 if (*len + newlen >= size) 90 bug(msg); 91 *len += newlen; 92 } 93 94 void 95 aps_log(struct aps *aps, int fd, int level, char *subject, char *fmt, ...) 96 { 97 char *p; 98 char buf[256]; 99 int len; 100 va_list ap, apc; 101 102 if (fmt == NULL || (aps && !(LOG_MASK(level) & aps->logmask))) 103 return; 104 105 len = 0; 106 107 if (fd) { 108 newbuflen(sizeof(buf), &len, snprintf(buf, sizeof(buf), 109 "client %d ", fd), "aps_log client"); 110 } 111 112 if (subject) { 113 assert(strchr(subject, '%') == NULL, "subject had % in it"); 114 newbuflen(sizeof(buf), &len, snprintf(buf + len, sizeof(buf) - len, 115 "%.16s ", subject), "aps_log subject"); 116 } 117 118 if (!(p = loglevelstr(level))) 119 bug("invalid log level"); 120 121 newbuflen(sizeof(buf), &len, snprintf(buf + len, sizeof(buf) - len, 122 "%s: %s", p, fmt), "aps_log level and user format"); 123 124 va_start(ap, fmt); 125 if (aps && aps->syslog) 126 vsyslog(level, buf, ap); 127 else { 128 newbuflen(sizeof(buf), &len, 129 strlcpy(buf + len, "\n", sizeof(buf) - len), "newline"); 130 vfprintf(stderr, buf, ap); 131 } 132 va_end(ap); 133 }