61 size_t len = strlen(path);
65 char* tmp = strdup(path);
69 if (tmp[len - 1] ==
'/')
72 for (
char* p = tmp + 1; *p; p++) {
75 if (mkdir(tmp, 0775) != 0 && errno != EEXIST) {
77 n_log(
LOG_ERR,
"could not create directory \"%s\": %s", tmp, strerror(error));
84 if (mkdir(tmp, 0775) != 0 && errno != EEXIST) {
86 n_log(
LOG_ERR,
"could not create directory \"%s\": %s", tmp, strerror(error));
107 const char* relative = NULL;
110 if (strncmp(filepath, kafka->
tosend_dir, base_len) == 0) {
111 relative = filepath + base_len;
112 while (*relative ==
'/')
117 if (relative && *relative) {
120 char* tmp = strdup(filepath);
128 char* dest_copy = strdup(
_nstr(dest));
135 if (rename(filepath,
_nstr(dest)) != 0) {
137 n_log(
LOG_ERR,
"could not move acknowledged file \"%s\" to \"%s\": %s", filepath,
_nstr(dest), strerror(error));
154 uint32_t raw_schema_id = 0;
155 memcpy(&raw_schema_id,
string + 1,
sizeof(uint32_t));
157 return (int32_t)ntohl(raw_schema_id);
180 uint32_t schema_id_htonl = htonl((uint32_t)schema_id);
181 memcpy(
string + 1, &schema_id_htonl,
sizeof(uint32_t));
227 if (error_timeout < 0) {
228 n_log(
LOG_ERR,
"n_kafka_set_error_timeout: negative timeout %d rejected", error_timeout);
275 if (rkmessage->err) {
281 if (event->parent_table)
284 event->error_time = time(NULL);
286 if (event->parent_table) {
287 event->parent_table->nb_waiting--;
288 event->parent_table->nb_error++;
290 if (event->parent_table)
291 unlock(event->parent_table->rwlock);
293 n_log(
LOG_DEBUG,
"message delivered (%ld bytes, partition %d)", rkmessage->len, rkmessage->partition);
296 if (event->parent_table)
300 if (event->event_files_to_delete) {
301 int move_to_sended = (
event->parent_table &&
event->parent_table->sended_dir) ? 1 : 0;
302 char** files_to_delete =
split(
_nstr(event->event_files_to_delete),
";", 0);
303 if (files_to_delete) {
306 while (files_to_delete[index]) {
307 if (move_to_sended) {
310 int ret = unlink(files_to_delete[index]);
313 n_log(
LOG_DEBUG,
"deleted on produce ack: %s", files_to_delete[index]);
315 n_log(
LOG_ERR,
"couldn't delete \"%s\": %s", files_to_delete[index], strerror(error));
329 if (event->parent_table)
330 unlock(event->parent_table->rwlock);
362 if (kafka->
mode == RD_KAFKA_CONSUMER) {
367 rd_kafka_topic_partition_list_destroy(kafka->
subscription);
369 if (kafka->
mode == RD_KAFKA_PRODUCER) {
449 n_log(
LOG_ERR,
"could not init kafka rwlock in kafka structure at address %p", kafka);
475 N_STR* config_string = NULL;
477 if (!config_string) {
483 json = cJSON_Parse(
_nstrp(config_string));
493 for (jsonIndex = 0; jsonIndex < cJSON_GetArraySize(json); jsonIndex++) {
494 cJSON* entry = cJSON_GetArrayItem(json, jsonIndex);
496 if (!entry)
continue;
498 if (!entry->valuestring) {
503 if (entry->string[0] !=
'-') {
505 if (strcmp(
"topic", entry->string) != 0 &&
506 strcmp(
"topics", entry->string) != 0 &&
507 strcmp(
"event_cmd", entry->string) != 0 &&
508 strcmp(
"value.schema.id", entry->string) != 0 &&
509 strcmp(
"value.schema.type", entry->string) != 0 &&
510 strcmp(
"poll.interval", entry->string) != 0 &&
511 strcmp(
"poll.timeout", entry->string) != 0 &&
512 strcmp(
"group.id.autogen", entry->string) != 0 &&
513 strcmp(
"monitored.directory.interval", entry->string) != 0) {
514 if (!strcmp(
"group.id", entry->string)) {
516 if (
mode == RD_KAFKA_PRODUCER)
518 kafka->
groupid = strdup(entry->valuestring);
524 n_log(
LOG_DEBUG,
"kafka config enabled: %s => %s", entry->string, entry->valuestring);
528 n_log(
LOG_DEBUG,
"kafka disabled config: %s => %s", entry->string, entry->valuestring);
535 jstr = cJSON_GetObjectItem(json,
"topic");
536 if (jstr && jstr->valuestring) {
537 kafka->
topic = strdup(jstr->valuestring);
540 if (
mode == RD_KAFKA_PRODUCER) {
548 jstr = cJSON_GetObjectItem(json,
"topics");
549 if (jstr && jstr->valuestring) {
553 if (
mode == RD_KAFKA_CONSUMER) {
562 jstr = cJSON_GetObjectItem(json,
"event_cmd");
563 if (jstr && jstr->valuestring) {
564 kafka->
event_cmd = strdup(jstr->valuestring);
565 n_log(
LOG_DEBUG,
"kafka consumer event_cmd: %s", jstr->valuestring);
569 jstr = cJSON_GetObjectItem(json,
"value.schema.id");
570 if (jstr && jstr->valuestring) {
571 int schem_v = atoi(jstr->valuestring);
572 if (schem_v < -1 || schem_v > 9999) {
583 jstr = cJSON_GetObjectItem(json,
"poll.interval");
584 if (jstr && jstr->valuestring) {
590 jstr = cJSON_GetObjectItem(json,
"poll.timeout");
591 if (jstr && jstr->valuestring) {
597 jstr = cJSON_GetObjectItem(json,
"monitored.directory.interval");
598 if (jstr && jstr->valuestring) {
604 jstr = cJSON_GetObjectItem(json,
"bootstrap.servers");
605 if (jstr && jstr->valuestring) {
610 if (
mode == RD_KAFKA_PRODUCER) {
614 jstr = cJSON_GetObjectItem(json,
"transactional.id");
615 if (jstr && jstr->valuestring && jstr->valuestring[0] !=
'\0') {
617 n_log(
LOG_DEBUG,
"kafka producer transactional.id: %s, enabling transactional produces", jstr->valuestring);
642 rd_kafka_error_t* txn_err = rd_kafka_init_transactions(kafka->
rd_kafka_handle, -1);
645 rd_kafka_error_destroy(txn_err);
652 kafka->
mode = RD_KAFKA_PRODUCER;
653 }
else if (
mode == RD_KAFKA_CONSUMER) {
667 char computer_name[1024] =
"";
672 jstr = cJSON_GetObjectItem(json,
"group.id.autogen");
673 if (jstr && jstr->valuestring) {
674 if (strcmp(jstr->valuestring,
"host-topic-group") == 0) {
676 nstrprintf(groupid,
"%s_%s", computer_name, topics);
677 }
else if (strcmp(jstr->valuestring,
"unique-group") == 0) {
679 nstrprintf(groupid,
"%s_%s_%d", computer_name, topics, getpid());
684 nstrprintf(groupid,
"%s_%s_%d", computer_name, topics, getpid());
685 n_log(
LOG_DEBUG,
"group.id is not set and group.id.autogen is not set, generated unique group id: %s",
_nstr(groupid));
689 groupid->
data = NULL;
728 kafka->
subscription = rd_kafka_topic_partition_list_new(topic_cnt);
729 for (
int i = 0; i < topic_cnt; i++)
733 RD_KAFKA_PARTITION_UA);
746 n_log(
LOG_ERR,
"kafka consumer: failed to subscribe to %d topics: %s", kafka->
subscription->cnt, rd_kafka_err2str(err));
752 n_log(
LOG_DEBUG,
"kafka consumer created and subscribed to %d topic(s), waiting for rebalance and messages...", kafka->
subscription->cnt);
754 kafka->
mode = RD_KAFKA_CONSUMER;
776 event->event_string = NULL;
777 event->event_files_to_delete = NULL;
778 event->from_topic = NULL;
779 event->rd_kafka_headers = NULL;
780 event->received_headers = NULL;
781 event->schema_id = schema_id;
783 event->parent_table = NULL;
784 event->error_time = 0;
802 event->rd_kafka_headers = rd_kafka_headers_new(count);
826 if (key_length < 1 || key_length > SSIZE_MAX) {
831 if (value_length < 1 || value_length > SSIZE_MAX) {
836 rd_kafka_resp_err_t err = rd_kafka_header_add(event->
rd_kafka_headers,
key, (ssize_t)key_length, value, (ssize_t)value_length);
839 n_log(
LOG_ERR,
"Failed to add header [%s:%zu=%s:%zu] to event %p%s: %s",
874 event->parent_table = kafka;
895 size_t event_length = 0;
897 event->parent_table = kafka;
900 event_length =
event->event_string->written;
903 rd_kafka_headers_t* hdrs_copy;
906 rd_kafka_resp_err_t err = rd_kafka_producev(
908 RD_KAFKA_V_PARTITION(RD_KAFKA_PARTITION_UA),
909 RD_KAFKA_V_MSGFLAGS(RD_KAFKA_MSG_F_COPY),
911 RD_KAFKA_V_HEADERS(hdrs_copy),
912 RD_KAFKA_V_OPAQUE((
void*)event),
916 rd_kafka_headers_destroy(hdrs_copy);
918 event->error_time = time(NULL);
919 n_log(
LOG_ERR,
"failed to produce event: %p%s with headers %p, producer: %p, topic: %s, error: %s", event,
n_kafka_event_fdesc(event), event->rd_kafka_headers, kafka->
rd_kafka_handle, kafka->
topic, rd_kafka_err2str(err));
923 if (rd_kafka_produce(kafka->
rd_kafka_topic, RD_KAFKA_PARTITION_UA, RD_KAFKA_MSG_F_COPY,
event_string, event_length, NULL, 0, event) == -1) {
926 event->error_time = time(NULL);
957 __n_assert(event->event_string, free(event);
return NULL);
960 size_t length = written + offset;
961 Malloc(event->event_string->data,
char, length);
962 __n_assert(event->event_string->data, free(event->event_string); free(event);
return NULL);
963 event->event_string->length = length;
966 memcpy(event->event_string->data + offset,
string, written);
967 event->event_string->written = written + offset;
1020 if (event->event_string)
1023 if (event->event_files_to_delete)
1024 free_nstr(&event->event_files_to_delete);
1028 if (event->rd_kafka_headers)
1029 rd_kafka_headers_destroy(event->rd_kafka_headers);
1031 if (event->received_headers)
1058 int event_consumption_enabled;
1059 int event_production_enabled;
1067 if (kafka->
mode == RD_KAFKA_PRODUCER) {
1068 if (event_production_enabled) {
1076 int txn_begin_failed = 0;
1093 rd_kafka_error_t* txn_err = rd_kafka_begin_transaction(kafka->
rd_kafka_handle);
1095 n_log(
LOG_ERR,
"could not begin transaction on producer %p, topic %s: %s%s", kafka->
rd_kafka_handle, kafka->
topic, rd_kafka_error_string(txn_err), rd_kafka_error_is_fatal(txn_err) ?
" (FATAL)" :
"");
1096 rd_kafka_error_destroy(txn_err);
1098 txn_begin_failed = 1;
1121 (time(NULL) - event->error_time) >= (time_t)kafka->
error_timeout) {
1124 event->error_time = 0;
1144 while (!committed && attempts < 5) {
1146 rd_kafka_error_t* commit_err = rd_kafka_commit_transaction(kafka->
rd_kafka_handle, -1);
1151 n_log(
LOG_ERR,
"could not commit transaction (attempt %d) on producer %p, topic %s: %s", attempts, kafka->
rd_kafka_handle, kafka->
topic, rd_kafka_error_string(commit_err));
1152 int retriable = rd_kafka_error_is_retriable(commit_err);
1153 int fatal = rd_kafka_error_is_fatal(commit_err);
1154 rd_kafka_error_destroy(commit_err);
1163 rd_kafka_error_t* abort_err = rd_kafka_abort_transaction(kafka->
rd_kafka_handle, -1);
1166 rd_kafka_error_destroy(abort_err);
1172 usleep((
unsigned int)(sleep_us > (uint64_t)UINT_MAX ? (uint64_t)UINT_MAX : sleep_us));
1174 }
else if (kafka->
mode == RD_KAFKA_CONSUMER) {
1175 if (event_consumption_enabled) {
1176 rd_kafka_message_t* rkm = NULL;
1185 n_log(
LOG_ERR,
"consumer: %s", rd_kafka_message_errstr(rkm));
1186 rd_kafka_message_destroy(rkm);
1188 usleep((
unsigned int)(sleep_us > (uint64_t)UINT_MAX ? (uint64_t)UINT_MAX : sleep_us));
1192 n_log(
LOG_DEBUG,
"Message on %s [%" PRId32
"] at offset %" PRId64
" (leader epoch %" PRId32
")", rd_kafka_topic_name(rkm->rkt), rkm->partition, rkm->offset, rd_kafka_message_leader_epoch(rkm));
1195 if (rkm->key && rkm->key_len > 0)
1196 n_log(
LOG_DEBUG,
"Key: %.*s", (
int)rkm->key_len, (
const char*)rkm->key);
1200 if (rkm->payload && rkm->len > 0) {
1205 event->parent_table = kafka;
1207 rd_kafka_headers_t* hdrs = NULL;
1208 if (!rd_kafka_message_headers(rkm, &hdrs)) {
1210 const char* name = NULL;
1211 const void* val = NULL;
1214 while (!rd_kafka_header_get_all(hdrs, idx, &name, &val, &size)) {
1215 N_STR* header_entry = NULL;
1222 event->from_topic = strdup(rd_kafka_topic_name(rkm->rkt));
1226 n_log(
LOG_DEBUG,
"Consumer received event of (%d bytes) from topic %s", (
int)rkm->len, event->from_topic);
1229 rd_kafka_message_destroy(rkm);
1233 usleep((
unsigned int)(sleep_us > (uint64_t)UINT_MAX ? (uint64_t)UINT_MAX : sleep_us));
1252 if (kafka->
mode == RD_KAFKA_PRODUCER)
1254 if (kafka->
mode == RD_KAFKA_CONSUMER) {
1262 int64_t remaining_time = (int64_t)kafka->
poll_timeout * 1000;
1263 while (status == 1) {
1265 if (kafka->
mode == RD_KAFKA_PRODUCER) {
1267 }
else if (kafka->
topics) {
1281 int64_t elapsed_time =
get_usec(&chrono);
1283 remaining_time -= elapsed_time;
1284 if (remaining_time < 0) {
1285 if (kafka->
mode == RD_KAFKA_PRODUCER) {
1287 }
else if (kafka->
mode == RD_KAFKA_CONSUMER) {
1318 n_log(
LOG_ERR,
"kafka polling thread already started for handle %p", kafka);
1326 n_log(
LOG_ERR,
"unable to create polling_thread for kafka handle %p", kafka);
1345 if (kafka->
mode == RD_KAFKA_CONSUMER) {
1353 if (polling_thread_status == 0) {
1354 n_log(
LOG_DEBUG,
"kafka polling thread already stopped for handle %p", kafka);
1357 if (polling_thread_status == 2) {
1358 n_log(
LOG_DEBUG,
"kafka polling ask for stop thread already done for handle %p", kafka);
1371 clock_gettime(CLOCK_REALTIME, &ts);
1376 n_log(
LOG_ERR,
"polling thread did not stop in 10s, force stop !");
1446 size_t nb_todump = 0;
1451 n_log(
LOG_ERR,
"kafka handle %p thread polling func is still running, aborting dump", kafka);
1455 if (nb_todump == 0) {
1456 n_log(
LOG_DEBUG,
"kafka handle %p: nothing to dump, all events processed correctly", kafka);
1463 N_STR* dumpstr = NULL;
1470 if (event->schema_id != -1)
1473 N_STR* filename = NULL;
1477 dumpstr->
data =
event->event_string->data + offset;
1478 dumpstr->
written =
event->event_string->written - offset;
1479 dumpstr->
length =
event->event_string->length - offset;
1486 dumpstr->
data = NULL;
#define init_lock(__rwlock_mutex)
Macro for initializing a rwlock.
#define FreeNoLog(__ptr)
Free Handler without log.
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
#define _str(__PTR)
define true
int get_computer_name(char *computer_name, size_t len)
get the computer name
#define rw_lock_destroy(__rwlock_mutex)
Macro to destroy rwlock mutex.
#define unlock(__rwlock_mutex)
Macro for releasing read/write lock a rwlock mutex.
#define _nstrp(__PTR)
N_STR or NULL pointer for testing purposes.
#define write_lock(__rwlock_mutex)
Macro for acquiring a write lock on a rwlock mutex.
#define Free(__ptr)
Free Handler to get errors.
#define read_lock(__rwlock_mutex)
Macro for acquiring a read lock on a rwlock mutex.
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
void * ptr
void pointer to store
LIST_NODE * start
pointer to the start of the list
struct LIST_NODE * next
pointer to the next node
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper, safe for node removal during iteration.
#define remove_list_node(__LIST_, __NODE_, __TYPE_)
Remove macro helper for void pointer casting.
int list_destroy(LIST **list)
Empty and Free a list container.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
Structure of a generic list node.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
#define LOG_INFO
informational
int32_t event_production_enabled
bool flag to suspend or restart event production
int32_t poll_interval
poll interval in msecs
rd_kafka_topic_partition_list_t * subscription
subscribed topics
int polling_thread_status
polling thread status, 0 => off , 1 => on , 2 => wants to stop, will be turned out to 0 by exiting po...
cJSON * configuration
kafka json configuration holder
size_t nb_waiting
number of events waiting for an ack in the waiting list
int mode
kafka handle mode: RD_KAFKA_CONSUMER or RD_KAFKA_PRODUCER
char ** topics
list of topics to subscribe to
rd_kafka_topic_t * rd_kafka_topic
kafka topic handle
rd_kafka_headers_t * rd_kafka_headers
kafka produce event headers structure handle
int32_t error_timeout
retry interval in seconds for events stuck in N_KAFKA_EVENT_ERROR.
int is_transactional
TRUE when a 'transactional.id' is set in the producer config: produces are then wrapped in kafka tran...
pthread_rwlock_t rwlock
access lock
N_STR * errstr
kafka error string holder
rd_kafka_conf_t * rd_kafka_conf
kafka structure handle
LIST * received_events
list of received N_KAFKA_EVENT
LIST * events_to_send
list of N_KAFKA_EVENT to send
int32_t poll_timeout
poll timeout in msecs
pthread_t polling_thread
polling thread id
char * sended_dir
base directory produced event files are moved to once acknowledged ('sended').
rd_kafka_t * rd_kafka_handle
kafka handle (producer or consumer)
char * event_cmd
eventual custom event_cmd
int32_t monitored_directory_interval
monitored directory refresh interval in msecs
char * tosend_dir
base directory the produced event files are read from ('to-send').
char * groupid
consumer group id
N_STR * event_files_to_delete
string containing the original event source file name if it is to be deleted when event is produced.
int32_t event_consumption_enabled
bool flag to suspend or restart event consumption
int schema_id
kafka schema id in network order
size_t nb_queued
number of waiting events in the producer waiting list
size_t nb_error
number of errored events
char * bootstrap_servers
kafka bootstrap servers string
char * topic
kafka topic string
int n_kafka_add_header_ex(N_KAFKA_EVENT *event, char *key, size_t key_length, char *value, size_t value_length)
add a header entry to an event.
int n_kafka_dump_unprocessed(N_KAFKA *kafka, char *directory)
dump unprocessed/unset events
N_KAFKA_EVENT * n_kafka_get_event(N_KAFKA *kafka)
get a received event from the N_KAFKA kafka handle
#define N_KAFKA_EVENT_OK
state of an OK event
int n_kafka_stop_polling_thread(N_KAFKA *kafka)
stop the polling thread of a kafka handle
#define N_KAFKA_EVENT_ERROR
state of an errored event
int32_t n_kafka_get_schema_from_nstr(const N_STR *string)
get a schema from the first 4 bytes of a N_STR *string, returning ntohl of the value
int n_kafka_new_headers(N_KAFKA_EVENT *event, size_t count)
allocate a headers array for the event
int n_kafka_put_schema_in_nstr(N_STR *string, int schema_id)
put a htonl schema id into the first 4 bytes of a N_STR *string
int n_kafka_enable_event_production(N_KAFKA *kafka)
enable event production
int n_kafka_disable_event_consumption(N_KAFKA *kafka)
disable event consumption
N_KAFKA * n_kafka_load_config(char *config_file, int mode)
load a kafka configuration from a file
int n_kafka_disable_event_production(N_KAFKA *kafka)
disable event production
int n_kafka_get_status(N_KAFKA *kafka, size_t *nb_queued, size_t *nb_waiting, size_t *nb_error)
return the queues status
#define N_KAFKA_EVENT_WAITING_ACK
state of a sent event waiting for acknowledgement
int n_kafka_put_schema_in_char(char *string, int schema_id)
put a htonl schema id into the first 4 bytes of a char *string
int n_kafka_poll(N_KAFKA *kafka)
Poll kafka handle in producer or consumer mode.
int n_kafka_start_polling_thread(N_KAFKA *kafka)
start the polling thread of a kafka handle
N_KAFKA_EVENT * n_kafka_new_event_from_char(const char *string, size_t written, int schema_id)
make a new event from a char *string
N_KAFKA_EVENT * n_kafka_new_event_from_string(const N_STR *string, int schema_id)
make a new event from a N_STR *string
int n_kafka_event_destroy(N_KAFKA_EVENT **event)
destroy a kafka event and set it's pointer to NULL
int n_kafka_enable_event_consumption(N_KAFKA *kafka)
enable event consumption
void n_kafka_event_destroy_ptr(void *event_ptr)
festroy a kafka event
int32_t n_kafka_get_schema_from_char(const char *string)
get a schema from the first 4 bytes of a char *string, returning ntohl of the value
int n_kafka_add_header(N_KAFKA_EVENT *event, N_STR *key, N_STR *value)
add a header entry to an event.
int n_kafka_set_sended_dir(N_KAFKA *kafka, const char *tosend_dir, const char *sended_dir)
set the 'to-send' and 'sended' base directories so acknowledged event files are moved instead of dele...
int n_kafka_load_unprocessed(N_KAFKA *kafka, const char *directory)
load unprocessed/unset events
int n_kafka_produce(N_KAFKA *kafka, N_KAFKA_EVENT *event)
put an event in the events_to_send list
N_KAFKA_EVENT * n_kafka_new_event(int schema_id)
create a new empty event
int n_kafka_set_error_timeout(N_KAFKA *kafka, int32_t error_timeout)
set the retry interval (in seconds) for events stuck in N_KAFKA_EVENT_ERROR
#define N_KAFKA_EVENT_CREATED
state of a freshly created event
N_KAFKA_EVENT * n_kafka_new_event_from_file(char *filename, int schema_id)
make a new event from a N_STR *string
N_KAFKA * n_kafka_new(int32_t poll_timeout, int32_t poll_interval, size_t errstr_len)
allocate a new kafka handle
#define N_KAFKA_EVENT_QUEUED
state of a queued event
void n_kafka_delete(N_KAFKA *kafka)
delete a N_KAFKA handle
structure of a KAFKA consumer or producer handle
structure of a KAFKA message
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
size_t length
total allocation (in bytes) of the data buffer, padding included
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
int split_count(char **split_result)
Count split elements.
int nstr_to_file(N_STR *str, char *filename)
Write a N_STR content into a file.
char * join(char **splitresult, const char *delim)
join the array into a string
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
char ** split(const char *str, const char *delim, int empty)
split the strings into a an array of char *pointer , ended by a NULL one.
N_STR * file_to_nstr(char *filename)
Load a whole file into a N_STR.
int free_split_result(char ***tab)
Free a split result allocated array.
A box including a string and his lenght.
int start_HiTimer(N_TIME *timer)
Initialize or restart from zero any N_TIME HiTimer.
time_t get_usec(N_TIME *timer)
Poll any N_TIME HiTimer, returning usec, and moving currentTime to startTime.
Base64 encoding and decoding functions using N_STR.
Common headers and low-level functions & define.
static int n_kafka_move_file_to_sended(const N_KAFKA *kafka, const char *filepath)
move a single acknowledged event file to the 'sended' directory, preserving its subpath relative to '...
static void n_kafka_delivery_message_callback(rd_kafka_t *rk, const rd_kafka_message_t *rkmessage, void *opaque)
Message delivery report callback.
static int n_kafka_mkdir_p(const char *path)
create a directory and all its missing parents (mkdir -p)
void * n_kafka_polling_thread(void *ptr)
kafka produce or consume polling thread function
int n_kafka_produce_ex(N_KAFKA *kafka, N_KAFKA_EVENT *event)
produce an event on a N_KAFKA *kafka handle
static const char * n_kafka_event_fdesc(const N_KAFKA_EVENT *event)
return a " (file: ...)" log fragment naming the source file(s) of an event
Kafka generic produce and consume event header.
#define _Thread_local
thread-local pre-connection error buffer (DNS, socket creation)