diff --git a/dev.conf b/dev.conf index 1980588e..15022e21 100644 --- a/dev.conf +++ b/dev.conf @@ -11,3 +11,4 @@ file_format = "%d:%ms [%V] %f:%L %m%n" *.* "./logs/%c.log", 50MB * 1 ~ "./logs/%c.#2s.log"; file_format *.* >stdout; stdout_format +*.* $remote_syslog; file_format diff --git a/neuron.json b/neuron.json index f96ee291..51b70c27 100644 --- a/neuron.json +++ b/neuron.json @@ -1,5 +1,7 @@ { "ip": "0.0.0.0", "port": 7000, - "disable_auth": 0 -} \ No newline at end of file + "disable_auth": 0, + "syslog_host": "", + "syslog_port": 541 +} diff --git a/src/argparse.c b/src/argparse.c index b13d92fe..25be4d13 100644 --- a/src/argparse.c +++ b/src/argparse.c @@ -78,6 +78,8 @@ const char *usage_text = " --config_file startup parameter configuration file\n" " --config_dir directory from which neuron reads configuration\n" " --plugin_dir directory from which neuron loads plugin lib files\n" +" --syslog_host syslog server host to which neuron will send logs\n" +" --syslog_port syslog server port (default 541 if not provided)\n" "\n"; // clang-format on @@ -225,6 +227,25 @@ static inline int load_env(neu_cli_args_t *args, char **log_level_out, } *plugin_dir_out = strdup(plugin_dir); } + + char *syslog_host = getenv(NEU_ENV_SYSLOG_HOST); + if (NULL != syslog_host) { + if (NULL != args->syslog_host) { + free(args->syslog_host); + } + args->syslog_host = strdup(syslog_host); + } + + char *syslog_port = getenv(NEU_ENV_SYSLOG_PORT); + if (NULL != syslog_port) { + int port = atoi(syslog_port); + if (port < 1 || 65535 < port) { + printf("neuron %s setting invalid!\n", NEU_ENV_SYSLOG_PORT); + ret = -1; + break; + } + args->syslog_port = port; + } } while (0); return ret; @@ -262,9 +283,13 @@ static inline int load_config_file(int argc, char *argv[], int fd = -1; void *root = NULL; - neu_json_elem_t elems[] = { { .name = "disable_auth", .t = NEU_JSON_INT }, - { .name = "ip", .t = NEU_JSON_STR }, - { .name = "port", .t = NEU_JSON_INT } }; + neu_json_elem_t elems[] = { + { .name = "disable_auth", .t = NEU_JSON_INT }, + { .name = "ip", .t = NEU_JSON_STR }, + { .name = "port", .t = NEU_JSON_INT }, + { .name = "syslog_host", .t = NEU_JSON_STR }, + { .name = "syslog_port", .t = NEU_JSON_INT }, + }; resolve_config_file_path(argc, argv, long_options, opts, &config_file); @@ -298,7 +323,8 @@ static inline int load_config_file(int argc, char *argv[], break; } - if (neu_json_decode_by_json(root, 3, elems) == 0) { + if (neu_json_decode_by_json(root, NEU_JSON_ELEM_SIZE(elems), elems) == + 0) { if (elems[0].v.val_int == 1) { args->disable_auth = true; } else if (elems[0].v.val_int == 0) { @@ -325,6 +351,24 @@ static inline int load_config_file(int argc, char *argv[], break; } + if (elems[3].v.val_str != NULL) { + if (strlen(elems[3].v.val_str) > 0) { + args->syslog_host = strdup(elems[3].v.val_str); + } + } else { + printf("config file %s syslog_host setting error!\n", + config_file); + break; + } + + if (0 < elems[4].v.val_int && elems[4].v.val_int < 65536) { + args->syslog_port = elems[4].v.val_int; + } else { + printf("config file %s syslog_port setting invalid!\n", + config_file); + break; + } + ret = 0; } else { printf("config file %s elems error! must had ip, port and " @@ -350,6 +394,10 @@ static inline int load_config_file(int argc, char *argv[], free(elems[1].v.val_str); } + if (elems[3].v.val_str != NULL) { + free(elems[3].v.val_str); + } + return ret; } @@ -374,6 +422,8 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[]) { "config_dir", required_argument, NULL, 'c' }, { "plugin_dir", required_argument, NULL, 'p' }, { "stop", no_argument, NULL, 's' }, + { "syslog_host", required_argument, NULL, 'S' }, + { "syslog_port", required_argument, NULL, 'P' }, { NULL, 0, NULL, 0 }, }; @@ -451,6 +501,22 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[]) } plugin_dir = strdup(optarg); break; + case 'P': { + int syslog_port = atoi(optarg); + if (syslog_port < 1 || 65535 < syslog_port) { + fprintf(stderr, "%s: option '--syslog_port' invalid : `%s`\n", + argv[0], optarg); + goto quit; + } + args->syslog_port = syslog_port; + break; + } + case 'S': + if (args->syslog_host) { + free(args->syslog_host); + } + args->syslog_host = strdup(optarg); + break; case '?': default: usage(); @@ -525,5 +591,6 @@ void neu_cli_args_fini(neu_cli_args_t *args) free(args->config_dir); free(args->plugin_dir); free(args->ip); + free(args->syslog_host); } } diff --git a/src/argparse.h b/src/argparse.h index 01a6cabb..8c0ab506 100644 --- a/src/argparse.h +++ b/src/argparse.h @@ -33,6 +33,8 @@ #define NEU_ENV_DISABLE_AUTH "NEURON_DISABLE_AUTH" #define NEU_ENV_CONFIG_DIR "NEURON_CONFIG_DIR" #define NEU_ENV_PLUGIN_DIR "NEURON_PLUGIN_DIR" +#define NEU_ENV_SYSLOG_HOST "NEURON_SYSLOG_HOST" +#define NEU_ENV_SYSLOG_PORT "NEURON_SYSLOG_PORT" #define NEURON_CONFIG_FNAME "./config/neuron.json" @@ -41,6 +43,7 @@ extern "C" { #endif #include +#include #include extern const char *g_config_dir; @@ -49,16 +52,18 @@ extern const char *g_plugin_dir; /** Neuron command line arguments. */ typedef struct { - bool daemonized; // flag indicating whether to run as daemon process - bool dev_log; // logging for development - size_t restart; // restart policy - bool disable_auth; - char * log_init_file; - char * config_dir; - char * plugin_dir; - bool stop; - char * ip; - int port; + bool daemonized; // flag indicating whether to run as daemon process + bool dev_log; // logging for development + size_t restart; // restart policy + bool disable_auth; + char * log_init_file; + char * config_dir; + char * plugin_dir; + bool stop; + char * ip; + int port; + char * syslog_host; + uint16_t syslog_port; } neu_cli_args_t; /** Parse command line arguments. diff --git a/src/main.c b/src/main.c index 57fc6fda..d7d9f9ed 100644 --- a/src/main.c +++ b/src/main.c @@ -17,8 +17,13 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ +#include +#include +#include #include #include +#include +#include #include #include @@ -39,6 +44,11 @@ char host_port[32] = { 0 }; int64_t global_timestamp = 0; +struct { + struct sockaddr_in addr; + int fd; +} g_remote_syslog_ctx; + static void sig_handler(int sig) { nlog_warn("recv sig: %d", sig); @@ -52,6 +62,40 @@ static void sig_handler(int sig) exit(-1); } +static int remote_syslog(zlog_msg_t *msg) +{ + sendto(g_remote_syslog_ctx.fd, msg->buf, msg->len, 0, + (const struct sockaddr *) &g_remote_syslog_ctx.addr, + sizeof(g_remote_syslog_ctx.addr)); + return 0; +} + +static int config_remote_syslog(const char *host, uint16_t port) +{ + g_remote_syslog_ctx.fd = socket(AF_INET, SOCK_DGRAM, 0); + if (g_remote_syslog_ctx.fd < 0) { + return -1; + } + + g_remote_syslog_ctx.addr.sin_family = AF_INET; + g_remote_syslog_ctx.addr.sin_port = htons(port); + g_remote_syslog_ctx.addr.sin_addr.s_addr = inet_addr(host); + + if (0 == inet_pton(AF_INET, host, &g_remote_syslog_ctx.addr.sin_addr)) { + // not an valid ip address, try resolve as host name + struct hostent *he = gethostbyname(host); + if (NULL == he) { + return -1; + } + + memcpy(&g_remote_syslog_ctx.addr.sin_addr, he->h_addr_list[0], + he->h_length); + } + + zlog_set_record("remote_syslog", remote_syslog); + return 0; +} + static int neuron_run(const neu_cli_args_t *args) { struct rlimit rl = { 0 }; @@ -107,8 +151,14 @@ int main(int argc, char *argv[]) } zlog_init(args.log_init_file); - neuron = zlog_get_category("neuron"); + if (args.syslog_host && strlen(args.syslog_host) > 0 && + 0 != config_remote_syslog(args.syslog_host, args.syslog_port)) { + nlog_fatal("neuron setup remote syslog fail, exit."); + goto main_end; + } + + neuron = zlog_get_category("neuron"); zlog_level_switch(neuron, default_log_level); if (neuron_already_running()) { diff --git a/zlog.conf b/zlog.conf index 2f2e8cbf..0fdc1a9f 100644 --- a/zlog.conf +++ b/zlog.conf @@ -9,3 +9,4 @@ simple = "%d:%ms [%V] %f:%L %m%n" [rules] *.* "./logs/%c.log", 50MB * 1 ~ "./logs/%c.#2s.log"; simple +*.* $remote_syslog; simple