3 #define __USE_GNU /* F_SETPIPE_SZ */
8 #include <murphy/common/log.h>
9 #include <murphy/common/mainloop.h>
11 #include "sphinx-plugin.h"
13 #define SPHINX_DEBUG "DEBUG: "
14 #define SPHINX_INFO "INFO: "
15 #define SPHINX_ERROR "ERROR: "
16 #define SPHINX_WARN "WARNING: "
17 #define SPHINX_SYSERR "SYSTEM_ERROR: "
18 #define SPHINX_FATAL "FATAL_ERROR: "
24 int fd[2]; /* log message pipe */
25 FILE *fp; /* log write stream */
26 mrp_io_watch_t *w; /* log I/O watch */
27 char buf[4096]; /* log line buffer */
32 static ssize_t pull_log(logger_t *logger)
37 p = logger->buf + logger->n;
38 l = sizeof(logger->buf) - logger->n - 1;
40 n = read(logger->fd[RD], p, l);
52 static char *dig_origin(char *msg, char *e, char *name, size_t size,
53 char **file, int *line)
55 char *nb, *ne, *lb, *le;
61 * Sphinx can prefix messages with a location header (file/line number)
62 * in at least two different formats:
64 * 1) file-name(line-number) message
65 * 2) "file-name", line line-number: message
67 * We assume we get a message with a location header in either of the
68 * above formats, try to dig out the location information and set the
69 * message pointer past the header. If we fail we pass the message
74 ne = strchr(nb + 1, '"');
76 if (ne == NULL || (ne > e && e != NULL)) {
79 *file = "<unknown file>";
83 if (strncmp(ne + 1, ", line ", 7))
87 l = (int)strtoul(lb + 1, &le, 10);
93 snprintf(name, size - 1, "%*.*s", nlen, nlen, nb + 1);
100 lb = strchr(msg, '(');
102 if (lb == NULL || lb > e)
105 l = (int)strtoul(lb + 1, &le, 10);
107 if (le[0] != ')' || le[1] != ':' || le[2] != ' ')
114 snprintf(name, size - 1, "%*.*s", nlen, nlen, nb);
121 if (*msg == ' ' || *msg == '\t') /* strip single leading space */
128 static void push_log(logger_t *logger)
130 char *b, *e, *lb, *le, *file, lvl, name[1024], *msg;
134 name[sizeof(name) - 1] = '\0';
140 while (logger->n > 0) {
143 if (!strncmp(b, SPHINX_INFO , len = sizeof(SPHINX_INFO ) - 1) ||
144 !strncmp(b, SPHINX_WARN , len = sizeof(SPHINX_WARN ) - 1) ||
145 !strncmp(b, SPHINX_ERROR , len = sizeof(SPHINX_ERROR ) - 1) ||
146 !strncmp(b, SPHINX_SYSERR, len = sizeof(SPHINX_SYSERR) - 1) ||
147 !strncmp(b, SPHINX_FATAL , len = sizeof(SPHINX_FATAL ) - 1)) {
154 if ((e = strchr(b, '\n')) == NULL) {
155 if (logger->n >= sizeof(logger->buf) - 1) {
156 mrp_log_warning("Discarding too long sphinx log buffer.");
162 mrp_debug("got log message '%s'", b);
165 msg = dig_origin(b, e, name, sizeof(name), &file, &line);
169 mrp_debug("stripped message '%s'", msg);
176 if (mrp_debug_check(file, "sphinx", line))
177 mrp_debug_msg("sphinx", line, file,
181 mrp_log_msg(MRP_LOG_WARNING, file, line, "sphinx",
187 mrp_log_msg(MRP_LOG_ERROR, file, line, "sphinx",
197 n = logger->n - (b - logger->buf);
202 memmove(logger->buf, b, n);
204 logger->buf[n] = '\0';
210 static void log_cb(mrp_io_watch_t *w, int fd, mrp_io_event_t events,
213 logger_t *logger = (logger_t *)user_data;
217 if (events & MRP_IO_EVENT_IN)
218 while (pull_log(logger) > 0)
221 if (events & MRP_IO_EVENT_HUP)
226 FILE *logger_create(context_t *ctx)
228 static logger_t logger = { { -1, -1 }, NULL, 0 };
229 mrp_mainloop_t *ml = plugin_get_mainloop(ctx->plugin);
230 mrp_io_event_t events = MRP_IO_EVENT_IN | MRP_IO_EVENT_HUP;
232 if (logger.fp != NULL)
235 if (pipe(logger.fd) < 0) {
236 mrp_log_error("Failed to create sphinx logging pipe (error %d: %s).",
237 errno, strerror(errno));
241 if ((logger.fp = fdopen(logger.fd[WR], "w")) == NULL)
244 setvbuf(logger.fp, NULL, _IOLBF, 0);
246 fcntl(logger.fd[WR], F_SETPIPE_SZ, 512 * 1024);
247 fcntl(logger.fd[WR], F_SETFL, O_NONBLOCK);
248 fcntl(logger.fd[RD], F_SETFL, O_NONBLOCK);
250 logger.w = mrp_add_io_watch(ml, logger.fd[RD], events, log_cb, &logger);
252 if (logger.w != NULL)
260 if (logger.fp != NULL)