include/cc_debug.h (126 lines of code) (raw):
/*
* ccommon - a cache common library.
* Copyright (C) 2013 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <cc_define.h>
#include <cc_option.h>
#include <cc_signal.h>
#include <stdint.h>
#define DEBUG_LOG_LEVEL 4 /* default log level */
#define DEBUG_LOG_FILE NULL /* default log file */
#define DEBUG_LOG_NBUF 0 /* default log buf size */
/* name type default description */
#define DEBUG_OPTION(ACTION) \
ACTION( debug_log_level, OPTION_TYPE_UINT, DEBUG_LOG_LEVEL, "debug log level" )\
ACTION( debug_log_file, OPTION_TYPE_STR, DEBUG_LOG_FILE, "debug log file" )\
ACTION( debug_log_nbuf, OPTION_TYPE_UINT, DEBUG_LOG_NBUF, "debug log buf size" )
typedef struct {
DEBUG_OPTION(OPTION_DECLARE)
} debug_options_st;
/**
* the debug module override the following signal handlers:
*
* - SIGTTIN: reload debug log file
* - SIGSEGV: print stacktrace before reraise segfault again
*/
/*
* Wrappers for defining custom assert based on whether macro
* CC_ASSERT_PANIC or CC_ASSERT_LOG was defined at the moment
* ASSERT was called.
*/
#if defined CC_ASSERT_PANIC && CC_ASSERT_PANIC == 1 /* log and panic */
#define ASSERT(_x) do { \
if (!(_x)) { \
debug_assert(#_x, __FILE__, __LINE__, 1); \
} \
} while (0)
#define NOT_REACHED() ASSERT(0)
#elif defined CC_ASSERT_LOG && CC_ASSERT_LOG == 1 /* just log */
#define ASSERT(_x) do { \
if (!(_x)) { \
debug_assert(#_x, __FILE__, __LINE__, 0); \
} \
} while (0)
#define NOT_REACHED() ASSERT(0)
#else /* ignore all asserts */
#define ASSERT(_x)
#define NOT_REACHED()
#endif
void debug_assert(const char *cond, const char *file, int line, int panic);
rstatus_i debug_setup(debug_options_st *options);
void debug_teardown(void);
/**
**********************************************
* Debug logging
**********************************************
*/
#define LOG_MAX_LEN 2560 /* max length of log message */
/*
* TODO(yao): a reasonable guideline for using these different levels.
*/
/* NOTE(yao): it may be useful to have a sampled log func for bursty events */
#define LOG_ALWAYS 0 /* always log, special value */
#define LOG_CRIT 1 /* critical: usually warrants exiting */
#define LOG_ERROR 2 /* error: may need action */
#define LOG_WARN 3 /* warning: may need attention */
#define LOG_INFO 4 /* informational: important but normal */
#define LOG_DEBUG 5 /* debug: abnormal behavior that's not an error */
#define LOG_VERB 6 /* verbose: showing normal logic flow */
#define LOG_VVERB 7 /* verbose on crack, for annoying msg e.g. timer */
struct logger;
struct timeout_event;
struct debug_logger {
struct logger *logger;
int level;
};
/* the default debug logger.
* This will be NULL as it points to a static variable declared in cc_debug.c
*/
extern struct debug_logger *dlog;
/*
* log_stderr - log to stderr
*
* loga - log always
* loga_hexdump - log hexdump always
*
* log_panic - log messages followed by a panic, when LOG_CRIT is met
* log_error - error log messages
* log_warn - warning log messages
* ...
*
* log - debug log messages based on a log level (subject to config)
* log_hexdump - hexadump -C of a log buffer (subject to config)
*/
#define loga(...) do { \
_log(dlog, __FILE__, __LINE__, LOG_ALWAYS, __VA_ARGS__); \
} while (0)
#define loga_hexdump(_data, _datalen, ...) do { \
_log(dlog, __FILE__,__LINE__, LOG_ALWAYS, __VA_ARGS__); \
_log_hexdump(dlog, -1, (char *)(_data), (int)(_datalen)); \
} while (0)
#define log_panic(...) do { \
_log(dlog, __FILE__, __LINE__, LOG_CRIT, __VA_ARGS__); \
abort(); \
} while (0)
/* the following can be compiled off */
#if defined CC_LOGGING && CC_LOGGING == 1
#define log_crit(...) do { \
if (dlog->level >= LOG_CRIT) { \
_log(dlog, __FILE__, __LINE__, LOG_CRIT, __VA_ARGS__); \
} \
} while (0)
#define log_error(...) do { \
if (dlog->level >= LOG_ERROR) { \
_log(dlog, __FILE__, __LINE__, LOG_ERROR, __VA_ARGS__); \
} \
} while (0)
#define log_warn(...) do { \
if (dlog->level >= LOG_WARN) { \
_log(dlog, __FILE__, __LINE__, LOG_WARN, __VA_ARGS__); \
} \
} while (0)
#define log_info(...) do { \
if (dlog->level >= LOG_INFO) { \
_log(dlog, __FILE__, __LINE__, LOG_INFO, __VA_ARGS__); \
} \
} while (0)
#define log_debug(...) do { \
if (dlog->level >= LOG_DEBUG) { \
_log(dlog, __FILE__, __LINE__, LOG_DEBUG, __VA_ARGS__); \
} \
} while (0)
#define log_verb(...) do { \
if (dlog->level >= LOG_VERB) { \
_log(dlog, __FILE__, __LINE__, LOG_VERB, __VA_ARGS__); \
} \
} while (0)
#define log_vverb(...) do { \
if (dlog->level >= LOG_VVERB) { \
_log(dlog, __FILE__, __LINE__, LOG_VVERB, __VA_ARGS__); \
} \
} while (0)
#define log_level(_level, ...) do { \
_log(dlog, __FILE__, __LINE__, _level, __VA_ARGS__); \
} while (0)
#define log_hexdump(_level, _data, _datalen, ...) do { \
_log(dlog, __FILE__,__LINE__, _level, __VA_ARGS__); \
_log_hexdump(dlog, _level, (char *)(_data), (int)(_datalen)); \
} while (0)
#else
#define log_crit(...)
#define log_error(...)
#define log_warn(...)
#define log_info(...)
#define log_debug(...)
#define log_verb(...)
#define log_vverb(...)
#define log_level(_level, ...)
#define log_hexdump(_level, _data, _datalen, ...)
#endif
void _log(struct debug_logger *dl, const char *file, int line, int level, const char *fmt, ...);
void _log_hexdump(struct debug_logger *dl, int level, char *data, int datalen);
void debug_log_flush(void *arg); /* compatible type: timeout_cb_fn */
#ifdef __cplusplus
}
#endif