void _log(int level, const char *file, int line, int panic, const char *fmt, ...) { struct logger *l = &logger; int len, size, errno_save; char buf[LOG_MAX_LEN]; va_list args; ssize_t n; struct timeval tv; if (l->fd < 0) { return; } errno_save = errno; len = 0; /* length of output buffer */ size = LOG_MAX_LEN; /* size of output buffer */ gettimeofday(&tv, NULL); buf[len++] = '['; len += (int)strftime(buf + len, (size_t)(size - len), "%Y-%m-%d %H:%M:%S.", localtime(&tv.tv_sec)); len += nc_scnprintf(buf + len, size - len, "%03d", (int)tv.tv_usec/1000); len += nc_scnprintf(buf + len, size - len, "] %6s [%"PRIu64"] ", log_level_s(level), gettid()); len += nc_scnprintf(buf + len, size - len, "%s:%d ", file, line); va_start(args, fmt); len += nc_vscnprintf(buf + len, size - len, fmt, args); va_end(args); buf[len++] = '\n'; n = nc_write(l->fd, buf, len); if (n < 0) { l->nerror++; } errno = errno_save; if (panic) { abort(); } }
/* * Unresolve the socket address by translating it to a character string * describing the host and service * * This routine is not reentrant */ char * nc_unresolve_addr(struct sockaddr *addr, socklen_t addrlen) { static char unresolve[NI_MAXHOST + NI_MAXSERV]; static char host[NI_MAXHOST], service[NI_MAXSERV]; int status; status = getnameinfo(addr, addrlen, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV); if (status < 0) { return "unknown"; } nc_scnprintf(unresolve, sizeof(unresolve), "%s:%s", host, service); return unresolve; }
/* Create a new slowlog entry. * Incrementing the ref count of all the objects retained is up to * this function. */ static slowlog_entry *slowlog_create_entry(struct msg *r, long long duration) { slowlog_entry *se = nc_alloc(sizeof(*se)); uint32_t j, keys_count, keys_count_input; se->cmdtype = r->type; keys_count_input = keys_count = r->keys==NULL?0:array_n(r->keys); if (keys_count_input > SLOWLOG_ENTRY_MAX_KEYS) keys_count_input = SLOWLOG_ENTRY_MAX_KEYS; se->keys_count = (int)keys_count; if (keys_count_input > 0) { se->keys = array_create(keys_count_input, sizeof(struct string)); for (j = 0; j < keys_count_input; j ++) { struct keypos *kp = array_get(r->keys, j); struct string *key = array_push(se->keys); uint32_t key_len = (uint32_t)(kp->end-kp->start); string_init(key); if (key_len > SLOWLOG_ENTRY_MAX_STRING) { int len; uint8_t buf[SLOWLOG_ENTRY_MAX_STRING+50]; memcpy(buf,kp->start,SLOWLOG_ENTRY_MAX_STRING); len = nc_scnprintf(buf+SLOWLOG_ENTRY_MAX_STRING, 50,"... (%lu more bytes)", key_len-SLOWLOG_ENTRY_MAX_STRING); if (len > 0) { string_copy(key,buf,SLOWLOG_ENTRY_MAX_STRING+(uint32_t)len); } else { string_copy(key,kp->start,SLOWLOG_ENTRY_MAX_STRING); } } else { string_copy(key,kp->start,key_len); } } }else { se->keys = NULL; } se->time = time(NULL); se->duration = duration; STAILQ_NEXT(se, next) = NULL; return se; }
struct msg * memcache_generate_error(struct msg *r, err_t err) { struct mbuf *mbuf; int n; char *protstr = "SERVER_ERROR"; char *errstr = err ? strerror(err) : "unknown"; r->type = MSG_RSP_MC_SERVER_ERROR; mbuf = mbuf_get(); if (mbuf == NULL) { return NULL; } mbuf_insert(&r->mhdr, mbuf); n = nc_scnprintf(mbuf->last, mbuf_size(mbuf), "%s %s"CRLF, protstr, errstr); mbuf->last += n; r->mlen = (uint32_t)n; return r; }
rstatus_t slowlog_command_make_reply(struct context *ctx, struct conn *conn, struct msg *msg, struct msg *pmsg) { rstatus_t status; uint32_t nkeys; struct keypos *kp; char *contents; uint32_t subcmdlen; ASSERT(conn->client && !conn->proxy); ASSERT(msg->request); ASSERT(pmsg != NULL && !pmsg->request); ASSERT(msg->owner == conn); ASSERT(conn->owner == ctx->manager); nkeys = array_n(msg->keys); ASSERT(nkeys >= 1); kp = array_get(msg->keys, 0); subcmdlen = (uint32_t)(kp->end-kp->start); if (subcmdlen==strlen("reset")&&!memcmp(kp->start,"reset",subcmdlen)){ if (nkeys != 1) { goto format_error; } slowlog_reset(); status = msg_append_full(pmsg, (uint8_t*)"OK", 2); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } else if (subcmdlen==strlen("id")&&!memcmp(kp->start,"id",subcmdlen)){ int buf_len; uint8_t buf[30]; long long id; if (nkeys != 1) { goto format_error; } pthread_rwlock_rdlock(&rwlocker); id = slowlog_entry_id; pthread_rwlock_unlock(&rwlocker); buf_len = nc_scnprintf(buf,30,"%lld",id); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } else if (subcmdlen==strlen("len")&&!memcmp(kp->start,"len",subcmdlen)){ int len, buf_len; uint8_t buf[20]; if (nkeys != 1) { goto format_error; } pthread_rwlock_rdlock(&rwlocker); len = slowlog_len; pthread_rwlock_unlock(&rwlocker); buf_len = nc_scnprintf(buf,20,"%d",len); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } else if (subcmdlen==strlen("get")&&!memcmp(kp->start,"get",subcmdlen)){ int count, sent = 0, buf_len; uint8_t buf[50]; slowlog_entry *se; struct string *str; if (nkeys == 1) { count = 10; } else if (nkeys == 2) { kp = array_get(msg->keys, 1); count = nc_atoi(kp->start, (kp->end-kp->start)); if (count < 0) { goto format_error; } } else { goto format_error; } pthread_rwlock_rdlock(&rwlocker); se = STAILQ_FIRST(&slowlog); while(count-- && se != NULL) { int nfield; uint32_t j; sent++; buf_len = nc_scnprintf(buf,50,"%d) 1) %lld\r\n",sent, se->id); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } buf_len = nc_scnprintf(buf,50," 2) %lld\r\n",se->time); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } buf_len = nc_scnprintf(buf,50," 3) %lld\r\n",se->duration); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } str = msg_type_string(se->cmdtype); nfield = 1; buf_len = nc_scnprintf(buf,50," 4) %d) %s\r\n",nfield++,str->data); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } buf_len = nc_scnprintf(buf,50," %d) %d\r\n",nfield++,se->keys_count); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } if (se->keys != NULL) { for (j = 0; j < array_n(se->keys); j ++) { str = array_get(se->keys, j); buf_len = nc_scnprintf(buf,50," %d) ",nfield++); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } status = msg_append_full(pmsg, str->data, (size_t)str->len); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } status = msg_append_full(pmsg, (uint8_t *)CRLF, CRLF_LEN); if (status != NC_OK) { pthread_rwlock_unlock(&rwlocker); conn->err = ENOMEM; return status; } } } se = STAILQ_NEXT(se, next); } pthread_rwlock_unlock(&rwlocker); if (msg_empty(pmsg)) { status = msg_append_full(pmsg, (uint8_t*)"END", 3); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } return NC_OK; } else if (subcmdlen==strlen("overview") && !memcmp(kp->start,"overview",subcmdlen)) { int count, buf_len; uint8_t buf[50]; int j, idx, id; struct statistics_oneday *so; if (nkeys == 1) { count = 10; } else if (nkeys == 2) { kp = array_get(msg->keys, 1); count = nc_atoi(kp->start, (kp->end-kp->start)); if (count < 0) { goto format_error; } } else { goto format_error; } if (slowlog_statistics == NULL) { status = msg_append_full(pmsg, (uint8_t*)"END", 3); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } if (count > statistics_days) count = statistics_days; pthread_mutex_lock(&statistics_locker); idx = today_idx; id = 1; while (count--) { so = &slowlog_statistics[idx]; if (so->year == 0) break; buf_len = nc_scnprintf(buf,50,"%d) %d-%d-%d ",id++,so->year+1900,so->mon+1,so->day); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_mutex_unlock(&statistics_locker); conn->err = ENOMEM; return status; } for (j = 0; j < statistics_period-1; j ++) { buf_len = nc_scnprintf(buf,50,"%lld ",so->periods[j]); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_mutex_unlock(&statistics_locker); conn->err = ENOMEM; return status; } } buf_len = nc_scnprintf(buf,50,"%lld\r\n",so->periods[statistics_period-1]); status = msg_append_full(pmsg, buf, (size_t)buf_len); if (status != NC_OK) { pthread_mutex_unlock(&statistics_locker); conn->err = ENOMEM; return status; } if (--idx < 0) { idx = statistics_days - 1; } } pthread_mutex_unlock(&statistics_locker); if (msg_empty(pmsg)) { status = msg_append_full(pmsg, (uint8_t*)"END", 3); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; } return NC_OK; } else { goto format_error; } format_error: contents = "ERR: slowlog command format is error."; status = msg_append_full(pmsg, (uint8_t *)contents, strlen(contents)); if (status != NC_OK) { conn->err = ENOMEM; return status; } goto done; done: status = msg_append_full(pmsg, (uint8_t *)CRLF, CRLF_LEN); if (status != NC_OK) { conn->err = ENOMEM; return status; } return NC_OK; }
/* * Hexadecimal dump in the canonical hex + ascii display * See -C option in man hexdump */ void _log_hexdump(const char *file, int line, char *data, int datalen, const char *fmt, ...) { struct logger *l = &logger; char buf[8 * LOG_MAX_LEN]; int i, off, len, size, errno_save; ssize_t n; if (l->fd < 0) { return; } /* log hexdump */ errno_save = errno; off = 0; /* data offset */ len = 0; /* length of output buffer */ size = 8 * LOG_MAX_LEN; /* size of output buffer */ while (datalen != 0 && (len < size - 1)) { char *save, *str; unsigned char c; int savelen; len += nc_scnprintf(buf + len, size - len, "%08x ", off); save = data; savelen = datalen; for (i = 0; datalen != 0 && i < 16; data++, datalen--, i++) { c = (unsigned char)(*data); str = (i == 7) ? " " : " "; len += nc_scnprintf(buf + len, size - len, "%02x%s", c, str); } for ( ; i < 16; i++) { str = (i == 7) ? " " : " "; len += nc_scnprintf(buf + len, size - len, " %s", str); } data = save; datalen = savelen; len += nc_scnprintf(buf + len, size - len, " |"); for (i = 0; datalen != 0 && i < 16; data++, datalen--, i++) { c = (unsigned char)(isprint(*data) ? *data : '.'); len += nc_scnprintf(buf + len, size - len, "%c", c); } len += nc_scnprintf(buf + len, size - len, "|\n"); off += 16; } n = nc_write(l->fd, buf, len); if (n < 0) { l->nerror++; } if (len >= size - 1) { n = nc_write(l->fd, "\n", 1); if (n < 0) { l->nerror++; } } errno = errno_save; }