diff options
author | Christoph Lipka <clipka@jp.adit-jv.com> | 2015-10-26 14:57:00 +0900 |
---|---|---|
committer | Lutz Helwing <lutz_helwing@mentor.com> | 2015-11-24 09:48:42 +0100 |
commit | d73717a4f6b243d40388bb1d3bb9db7421d7b9b0 (patch) | |
tree | 091f25b5f38257f611733e4757b762a036b12d83 /src | |
parent | 5574d46a4083d783a915688e0e05593b9558497b (diff) | |
download | DLT-daemon-d73717a4f6b243d40388bb1d3bb9db7421d7b9b0.tar.gz |
DltLogstorage: Logstorage Cache
When using DltLogstorage on internal storage device, it is needed to
reduce writing to internal storage device as much as possible.
This patch introduces sync strategies to Logstorage to provide that
functionality.
The ON_MSG strategy is the default sync strategy that flushes every
written log message to the storage device (fflush).
The ON_DAEMON_EXIT strategy only flushes data to disk when the daemon
exits.
The strategy can be defined per filter in the dlt_logstorage.conf
configuration file by adding
SyncBehavior=<Strategy> to a configuration.
Signed-off-by: Christoph Lipka <clipka@jp.adit-jv.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/daemon/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/daemon/dlt-daemon.c | 29 | ||||
-rw-r--r-- | src/daemon/dlt-daemon.h | 1 | ||||
-rw-r--r-- | src/daemon/dlt.conf | 3 | ||||
-rw-r--r-- | src/daemon/dlt_daemon_offline_logstorage.c | 32 | ||||
-rw-r--r-- | src/daemon/dlt_daemon_offline_logstorage.h | 19 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage.c | 630 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage.h | 57 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage_behavior.c | 868 | ||||
-rw-r--r-- | src/offlinelogstorage/dlt_offline_logstorage_behavior.h | 91 |
10 files changed, 1224 insertions, 508 deletions
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index f665a4d..128dbe8 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -20,7 +20,7 @@ if(WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD) message( STATUS "Added ${systemd_SRCS} to dlt-daemon") endif(WITH_SYSTEMD_WATCHDOG OR WITH_SYSTEMD) -set(dlt_daemon_SRCS dlt-daemon.c dlt_daemon_common.c dlt_daemon_connection.c dlt_daemon_event_handler.c dlt_daemon_socket.c dlt_daemon_unix_socket.c dlt_daemon_serial.c dlt_daemon_client.c dlt_daemon_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_user_shared.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_common.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_shm.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_offline_trace.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_config_file_parser.c) +set(dlt_daemon_SRCS dlt-daemon.c dlt_daemon_common.c dlt_daemon_connection.c dlt_daemon_event_handler.c dlt_daemon_socket.c dlt_daemon_unix_socket.c dlt_daemon_serial.c dlt_daemon_client.c dlt_daemon_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_user_shared.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_common.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_shm.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_offline_trace.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage.c ${CMAKE_SOURCE_DIR}/src/shared/dlt_config_file_parser.c ${CMAKE_SOURCE_DIR}/src/offlinelogstorage/dlt_offline_logstorage_behavior.c) add_executable(dlt-daemon ${dlt_daemon_SRCS} ${systemd_SRCS}) target_link_libraries(dlt-daemon rt ${CMAKE_THREAD_LIBS_INIT}) diff --git a/src/daemon/dlt-daemon.c b/src/daemon/dlt-daemon.c index 61aca56..02e42ec 100644 --- a/src/daemon/dlt-daemon.c +++ b/src/daemon/dlt-daemon.c @@ -84,6 +84,8 @@ static int dlt_daemon_log_internal(DltDaemon *daemon, DltDaemonLocal *daemon_loc static uint32_t watchdog_trigger_interval; // watchdog trigger interval in [s] #endif +/* used in main event loop and signal handler */ +int g_exit = 0; /** * Print usage information of tool. @@ -238,6 +240,9 @@ int option_file_parser(DltDaemonLocal *daemon_local) daemon_local->flags.offlineLogstorageDelimiter = '_'; daemon_local->flags.offlineLogstorageMaxCounter = UINT_MAX; daemon_local->flags.offlineLogstorageMaxCounterIdx = 0; + daemon_local->flags.offlineLogstorageCacheSize = 30000; /* 30MB */ + dlt_daemon_logstorage_set_logstorage_cache_size( + daemon_local->flags.offlineLogstorageCacheSize); strncpy(daemon_local->flags.ctrlSockPath, DLT_DAEMON_DEFAULT_CTRL_SOCK_PATH, sizeof(daemon_local->flags.ctrlSockPath) - 1); @@ -459,6 +464,13 @@ int option_file_parser(DltDaemonLocal *daemon_local) daemon_local->flags.offlineLogstorageMaxCounter = atoi(value); daemon_local->flags.offlineLogstorageMaxCounterIdx = strlen(value); } + else if(strcmp(token, "OfflineLogstorageCacheSize") == 0) + { + daemon_local->flags.offlineLogstorageCacheSize = + (unsigned int)atoi(value); + dlt_daemon_logstorage_set_logstorage_cache_size( + daemon_local->flags.offlineLogstorageCacheSize); + } else if(strcmp(token,"ControlSocketPath") == 0) { memset( @@ -499,7 +511,7 @@ int main(int argc, char* argv[]) char version[DLT_DAEMON_TEXTBUFSIZE]; DltDaemonLocal daemon_local; DltDaemon daemon; - int back; + int back = 0; /* Command line option handling */ if ((back = option_handling(&daemon_local,argc,argv))<0) @@ -637,7 +649,7 @@ int main(int argc, char* argv[]) dlt_daemon_log_internal(&daemon, &daemon_local, "Daemon launched. Starting to output traces...", daemon_local.flags.vflag); /* Even handling loop. */ - while (back >= 0) + while ((back >= 0) && (g_exit >= 0)) { back = dlt_daemon_handle_event(&daemon_local.pEvent, &daemon, @@ -647,7 +659,13 @@ int main(int argc, char* argv[]) dlt_daemon_log_internal(&daemon, &daemon_local, "Exiting Daemon...", daemon_local.flags.vflag); - dlt_daemon_local_cleanup(&daemon, &daemon_local, daemon_local.flags.vflag); + /* disconnect all logstorage devices */ + dlt_daemon_logstorage_cleanup(&daemon, + &daemon_local, + daemon_local.flags.vflag); + + +// dlt_daemon_local_cleanup(&daemon, &daemon_local, daemon_local.flags.vflag); dlt_log(LOG_NOTICE, "Leaving DLT daemon\n"); @@ -1167,9 +1185,8 @@ void dlt_daemon_signal_handler(int sig) tmp[PATH_MAX] = 0; unlink(tmp); - - /* Terminate program */ - exit(0); + /* stop event loop */ + g_exit = -1; break; } default: diff --git a/src/daemon/dlt-daemon.h b/src/daemon/dlt-daemon.h index 503a98f..02a55b3 100644 --- a/src/daemon/dlt-daemon.h +++ b/src/daemon/dlt-daemon.h @@ -118,6 +118,7 @@ typedef struct char offlineLogstorageDelimiter; /**< (char) Append delimeter character in offline logstorage filename */ unsigned int offlineLogstorageMaxCounter; /**< (int) Maximum offline logstorage file counter index until wraparound */ unsigned int offlineLogstorageMaxCounterIdx; /**< (int) String len of offlineLogstorageMaxCounter*/ + unsigned int offlineLogstorageCacheSize; /**< Max cache size offline logstorage cache */ char userPipesDir[NAME_MAX + 1]; /**< (String: Directory) directory where dltpipes reside (Default: /tmp/dltpipes) */ char daemonFifoName[NAME_MAX + 1]; /**< (String: Filename) name of local fifo (Default: /tmp/dlt) */ unsigned int port; /**< port number */ diff --git a/src/daemon/dlt.conf b/src/daemon/dlt.conf index 72377e5..5deec60 100644 --- a/src/daemon/dlt.conf +++ b/src/daemon/dlt.conf @@ -145,3 +145,6 @@ ControlSocketPath = /tmp/dlt-ctrl.sock # Wrap around value for log file count in file name (Default: UINT_MAX) # OfflineLogstorageMaxCounter = 999 + +# Maximal used memory for Logstorage Cache in KB (Default: 30000 KB) +# OfflineLogstorageCacheSize = 30000
\ No newline at end of file diff --git a/src/daemon/dlt_daemon_offline_logstorage.c b/src/daemon/dlt_daemon_offline_logstorage.c index bc8817c..66f9ec8 100644 --- a/src/daemon/dlt_daemon_offline_logstorage.c +++ b/src/daemon/dlt_daemon_offline_logstorage.c @@ -565,3 +565,35 @@ int dlt_daemon_logstorage_setup_internal_storage(DltDaemon *daemon, char *path, return ret; } + +void dlt_daemon_logstorage_set_logstorage_cache_size(unsigned int size) +{ + /* store given [KB] size in [Bytes] */ + g_logstorage_cache_max = size * 1000; +} + +int dlt_daemon_logstorage_cleanup(DltDaemon *daemon, + DltDaemonLocal *daemon_local, + int verbose) +{ + int i = 0; + + PRINT_FUNCTION_VERBOSE(verbose); + + if (daemon == NULL || daemon_local == NULL) + { + return -1; + } + + for (i = 0; i < daemon_local->flags.offlineLogstorageMaxDevices; i++) + { + /* call disconnect on all currently connected devices */ + if (daemon->storage_handle[i].connection_type == + DLT_OFFLINE_LOGSTORAGE_DEVICE_CONNECTED) + { + dlt_logstorage_device_disconnected(&daemon->storage_handle[i]); + } + } + + return 0; +} diff --git a/src/daemon/dlt_daemon_offline_logstorage.h b/src/daemon/dlt_daemon_offline_logstorage.h index 621bd59..cb7698a 100644 --- a/src/daemon/dlt_daemon_offline_logstorage.h +++ b/src/daemon/dlt_daemon_offline_logstorage.h @@ -126,4 +126,23 @@ void dlt_daemon_logstorage_write(DltDaemon *daemon, DltDaemonFlags user_config, * @param verbose If set to true verbose information is printed out */ int dlt_daemon_logstorage_setup_internal_storage(DltDaemon *daemon, char *path, int verbose); + +/** + * Set max size of logstorage cache. Stored internally in bytes + * + * @param size Size of logstorage cache [in KB] + */ +void dlt_daemon_logstorage_set_logstorage_cache_size(unsigned int size); + +/** + * Cleanup dlt logstorage + * + * @param daemon Pointer to Dlt Daemon structure + * @param daemon_local Pointer to Dlt Daemon Local structure + * @param verbose If set to true verbose information is printed out + */ +int dlt_daemon_logstorage_cleanup(DltDaemon *daemon, + DltDaemonLocal *daemon_local, + int verbose); + #endif /* DLT_DAEMON_OFFLINE_LOGSTORAGE_H */ diff --git a/src/offlinelogstorage/dlt_offline_logstorage.c b/src/offlinelogstorage/dlt_offline_logstorage.c index 682fe55..d1efbb5 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage.c +++ b/src/offlinelogstorage/dlt_offline_logstorage.c @@ -32,6 +32,7 @@ #include <time.h> #include "dlt_offline_logstorage.h" +#include "dlt_offline_logstorage_behavior.h" #include "dlt_config_file_parser.h" @@ -312,6 +313,41 @@ int dlt_logstorage_read_number(unsigned int *number, char *value) return 0; } +/** + * dlt_logstorage_set_sync_strategy + * + * Evaluate sync strategy. The sync strategy is an optional filter + * configuration parameter. + * If the given value cannot be associated with a sync strategy, the default + * sync strategy will be assigned. + * + * @param file_name int to store the sync strategy + * @param value string given in config file + * @return 0 on success, -1 on error + */ +int dlt_logstorage_set_sync_strategy(int *strategy, char *value) +{ + if (value == NULL || strategy == NULL) + { + return -1; + } + + if (strncasecmp(value, "ON_MSG", strlen(value)) == 0) + { + *strategy = DLT_LOGSTORAGE_SYNC_ON_MSG; + } + else if (strncasecmp(value, "ON_DAEMON_EXIT", strlen(value)) == 0) + { + *strategy = DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT; + } + else + { + dlt_log(LOG_WARNING, "Unknown sync strategy. Set default ON_MSG\n"); + *strategy = DLT_LOGSTORAGE_SYNC_ON_MSG; + } + + return 0; +} /** * dlt_logstorage_create_keys @@ -518,10 +554,23 @@ void dlt_logstorage_free(DltLogStorage *handle) for(i=0; i<handle->num_filter_keys; i++) { + /* sync data if necessary */ + /* ignore return value */ + handle->config_data[i].data.dlt_logstorage_sync( + &(handle->config_data[i].data), + DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT); + free(handle->config_data[i].data.file_name); if (handle->config_data[i].data.log != NULL) - fclose(handle->config_data[i].data.log); + { + fclose(handle->config_data[i].data.log); + } + + if (handle->config_data[i].data.cache != NULL) + { + free(handle->config_data[i].data.cache); + } DltLogStorageFileList *n = handle->config_data[i].data.records; while(n) @@ -624,6 +673,8 @@ int dlt_logstorage_prepare_table(DltLogStorage *handle, char *appid, char *ctxid memcpy(&p_node->data, tmp_data, sizeof(DltLogStorageConfigData)); p_node->data.file_name = strdup(tmp_data->file_name); p_node->data.records = NULL; + p_node->data.log = NULL; + p_node->data.cache = NULL; if(dlt_logstorage_hash_add(p_node->key, &p_node->data, &(handle->config_htab)) != 0) { @@ -703,6 +754,14 @@ int dlt_logstorage_validate_filter_value(char *filter_key, char *filter_value, if (ret == 0) ret = DLT_OFFLINE_LOGSTORAGE_NUM_INIT; } + else if (strncmp(filter_key, "SyncBehavior", strlen ("SyncBehavior")) == 0) + { + ret = dlt_logstorage_set_sync_strategy(&(tmp_data->sync), filter_value); + if (ret == 0) + { + return DLT_OFFLINE_LOGSTORAGE_SYNC_BEHAVIOR; + } + } else { /* Invalid filter key */ @@ -754,6 +813,29 @@ int dlt_logstorage_validate_filter_name(char *name) return -1; } +void dlt_logstorage_filter_set_strategy(DltLogStorageConfigData *config, + int strategy) +{ + if (config == NULL) + { + return; + } + + switch(strategy) + { + case DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT: + config->dlt_logstorage_prepare = &dlt_logstorage_prepare_on_daemon_exit; + config->dlt_logstorage_write = &dlt_logstorage_write_on_daemon_exit; + config->dlt_logstorage_sync = &dlt_logstorage_sync_on_daemon_exit; + break; + case DLT_LOGSTORAGE_SYNC_ON_MSG: /* ON_MSG is the default strategy */ + default: + config->dlt_logstorage_prepare = &dlt_logstorage_prepare_on_msg; + config->dlt_logstorage_write = &dlt_logstorage_write_on_msg; + config->dlt_logstorage_sync = &dlt_logstorage_sync_on_msg; + } +} + /** * dlt_logstorage_store_filters * @@ -783,7 +865,8 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) "LogLevel", "File", "FileSize", - "NOFiles" + "NOFiles", + "SyncBehavior" }; config_file = dlt_config_file_init(config_file_name); @@ -805,6 +888,7 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) int j = 0; int ret = -1; memset(&tmp_data, 0, sizeof(DltLogStorageConfigData)); + for (i = 0; i < num_filters; i++) { if (tmp_data.file_name != NULL) @@ -841,7 +925,9 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) { /* Get filter value for filter keys */ ret = dlt_config_file_get_value(config_file, filter_name, filter_key[j], filter_value); - if (ret != 0) + if (ret != 0 && + strncmp(filter_key[j], "SyncBehavior", strlen(filter_key[j])) + != 0) { is_filter_set = DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT; dlt_log(LOG_ERR, "dlt_logstorage_store_filters Error : Reading filter value failed\n"); @@ -849,20 +935,35 @@ int dlt_logstorage_store_filters(DltLogStorage *handle, char *config_file_name) } /* Validate filter value */ - ret = dlt_logstorage_validate_filter_value(filter_key[j], filter_value, &appid, &ctxid, &tmp_data); - if ((ret != -1) && DLT_OFFLINE_LOGSTORAGE_IS_FILTER_PRESENT(is_filter_set)) + if (ret == 0) { - is_filter_set |= ret; + ret = dlt_logstorage_validate_filter_value(filter_key[j], filter_value, &appid, &ctxid, &tmp_data); + if ((ret != -1) && DLT_OFFLINE_LOGSTORAGE_IS_FILTER_PRESENT(is_filter_set)) + { + is_filter_set |= ret; + } + else + { + is_filter_set = DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT; + break; + } } else { - is_filter_set = DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT; - break; + dlt_log(LOG_INFO, + "Sync strategy not given. Use default ON_MSG\n"); + /* set default sync strategy */ + tmp_data.sync = DLT_LOGSTORAGE_SYNC_ON_MSG; } } + /* If all items of the filter is populated store them */ if (DLT_OFFLINE_LOGSTORAGE_FILTER_INITIALIZED(is_filter_set)) { + /* depending on the specified strategy set function pointers for + * prepare, write and sync */ + dlt_logstorage_filter_set_strategy(&tmp_data, tmp_data.sync); + ret = dlt_logstorage_prepare_table(handle, appid, ctxid, &tmp_data); if (ret != 0) { @@ -1088,469 +1189,6 @@ DltLogStorageConfigData **dlt_logstorage_filter(DltLogStorage *handle, char *app } /** - * dlt_logstorage_log_file_name - * - * Create log file name in the form configured by the user - * <filename><delimeter><index><delimeter><timestamp>.dlt - * - * filename: given in configuration file - * delimeter: Punctuation characters (configured in dlt.conf) - * timestamp: yyyy-mm-dd-hh-mm-ss (enabled/disabled in dlt.conf) - * index: Index len depends on wrap around value in dlt.conf - * ex: wrap around = 99, index will 01..99 - * - * @param log_file_name contains complete logfile name - * @param file_config User configurations for log file - * @param name file name given in configuration file - * @param idx continous index of log files - * @ return None - */ -void dlt_logstorage_log_file_name(char *log_file_name, DltLogStorageUserConfig file_config, char *name, int idx) -{ - char file_index[10] = {0}; - - // create log file name - memset(log_file_name, 0, PATH_MAX * sizeof(char)); - strcat(log_file_name, name); - strcat(log_file_name, &file_config.logfile_delimiter); - - sprintf(file_index,"%d",idx); - if(file_config.logfile_maxcounter != UINT_MAX) - { - /* Setup 0's to be appended in file index until max index len*/ - unsigned int digit_idx = 0; - unsigned int i = 0; - sprintf(file_index,"%d",idx); - digit_idx = strlen(file_index); - for(i=0; i<(file_config.logfile_counteridxlen - digit_idx); i++) { - strcat(log_file_name, "0"); - } - } - strcat(log_file_name, file_index); - - /* Add time stamp if user has configured */ - if(file_config.logfile_timestamp) - { - char stamp[DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + 1] = {0}; - time_t t = time(NULL); - struct tm *tm_info = localtime(&t); - sprintf(stamp, "%c%04d%02d%02d-%02d%02d%02d", file_config.logfile_delimiter, 1900 + tm_info->tm_year, 1 + tm_info->tm_mon, - tm_info->tm_mday, tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec); - strcat(log_file_name, stamp); - } - - strcat(log_file_name, ".dlt"); -} - -/** - * dlt_logstorage_sort_file_name - * - * Sort the filenames with index based ascending order (bubble sort) - * - * @param head Log filename list - * @ return None - */ -void dlt_logstorage_sort_file_name(DltLogStorageFileList **head) -{ - int done = 0; - - if (*head == NULL || (*head)->next == NULL) - return; - - while (!done) - { - DltLogStorageFileList **pv = head; // "source" of the pointer to the current node in the list struct - DltLogStorageFileList *nd = *head; // local iterator pointer - DltLogStorageFileList *nx = (*head)->next; // local next pointer - - done = 1; - - while (nx) - { - if (nd->idx > nx->idx) - { - nd->next = nx->next; - nx->next = nd; - *pv = nx; - - done = 0; - } - pv = &nd->next; - nd = nx; - nx = nx->next; - } - } -} - -/** - * dlt_logstorage_rearrange_file_name - * - * Rearrange the filenames in the order of latest and oldest - * - * @param head Log filename list - * @ return None - */ -void dlt_logstorage_rearrange_file_name(DltLogStorageFileList **head) -{ - DltLogStorageFileList *n_prev = NULL; - DltLogStorageFileList *tail = NULL; - DltLogStorageFileList *wrap_pre = NULL; - DltLogStorageFileList *wrap_post = NULL; - DltLogStorageFileList *n = NULL; - - if (*head == NULL || (*head)->next == NULL) - return; - - for (n = *head; n != NULL; n = n->next ) - { - if (n && n_prev) - { - if ((n->idx - n_prev->idx) != 1) - { - wrap_post = n; - wrap_pre = n_prev; - } - } - n_prev = n; - } - tail = n_prev; - - if (wrap_post && wrap_pre) - { - wrap_pre->next = NULL; - tail->next = *head; - *head = wrap_post; - } -} - -/** - * dlt_logstorage_get_idx_of_log_file - * - * Extract index of log file name passed as input argument - * - * @param file file name to extract the index from - * @param file_config User configurations for log file - * @return index on success, -1 if no index is found - */ -unsigned int dlt_logstorage_get_idx_of_log_file(DltLogStorageUserConfig file_config, char *file) -{ - unsigned int idx = -1; - char *endptr; - char *filename; - unsigned int filename_len = 0 ; - unsigned int fileindex_len = 0; - - /* Calculate actual file name length */ - filename=strchr(file,file_config.logfile_delimiter); - filename_len = strlen(file)- strlen(filename); - - /* index is retrived from file name */ - if(file_config.logfile_timestamp) - { - fileindex_len = strlen(file)-(DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN - + DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + filename_len + 1); - idx = (int) strtol(&file[strlen(file)- - (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN+fileindex_len - +DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN)], - &endptr, 10); - } - else - { - fileindex_len = strlen(file)-(DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + filename_len + 1); - idx = (int) strtol(&file[strlen(file)- - (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN - +fileindex_len)], &endptr, 10); - } - - if(endptr == file || idx == 0) - dlt_log(LOG_ERR, "Unable to calculate index from log file name. Reset index to 001.\n"); - - return idx; -} - -/** - * dlt_logstorage_storage_dir_info - * - * Read file names of storage directory. - * Update the file list, arrange it in order of latest and oldest - * - * @param file_config User configurations for log file - * @param path Path to storage directory - * @param config DltLogStorageConfigData - * @return 0 on success, -1 on error - */ -int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig file_config, char *path, DltLogStorageConfigData *config) -{ - int i = 0; - int cnt = 0; - int ret = 0; - struct dirent **files = {0}; - unsigned int current_idx = 0; - - if (path == NULL || config->file_name == NULL) - return -1; - - cnt = scandir(path, &files, 0, alphasort); - if (cnt < 0) - { - dlt_log(LOG_ERR, "dlt_logstorage_storage_dir_info: Unable to scan storage directory.\n"); - return -1; - } - - for (i = 0; i < cnt; i++) - { - int len = 0; - len = strlen(config->file_name); - if ((strncmp(files[i]->d_name, config->file_name, len) == 0) && (files[i]->d_name[len] == file_config.logfile_delimiter)) - { - DltLogStorageFileList **tmp = NULL; - current_idx = dlt_logstorage_get_idx_of_log_file(file_config, files[i]->d_name); - - if(config->records == NULL) - { - config->records = malloc(sizeof(DltLogStorageFileList)); - if (config->records == NULL) - { - ret = -1; - dlt_log(LOG_ERR, "Memory allocation failure while preparing file list \n"); - break; - } - tmp = &config->records; - } - else - { - tmp = &config->records; - while(*(tmp) != NULL) - { - tmp = &(*tmp)->next; - } - *tmp = malloc(sizeof(DltLogStorageFileList)); - if (*tmp == NULL) - { - ret = -1; - dlt_log(LOG_ERR, "Memory allocation failure while preparing file list \n"); - break; - } - } - (*tmp)->name = strdup(files[i]->d_name); - (*tmp)->idx = current_idx; - (*tmp)->next = NULL; - } - } - - if (ret == 0) - { - dlt_logstorage_sort_file_name(&config->records); - dlt_logstorage_rearrange_file_name(&config->records); - } - - /* free scandir result */ - for (i = 0; i < cnt; i++) - { - free(files[i]); - } - free(files); - - return ret; -} - -/** - * dlt_logstorage_open_log_file - * - * Open a log file. Check storage directory for already created files and open the oldest if - * there is enough space to store at least msg_size. - * Otherwise create a new file, but take configured max number of files into account and remove - * the oldest file if needed. - * - * @param config DltLogStorageConfigData - * @param file_config User configurations for log file - * @param dev_path Storage device path - * @param msg_size Size of incoming message - * @return 0 on succes, -1 on error - */ -int dlt_logstorage_open_log_file(DltLogStorageConfigData *config, DltLogStorageUserConfig file_config, - char *dev_path, int msg_size) -{ - int ret = 0; - char absolute_file_path[PATH_MAX + 1] = {0}; - char storage_path[DLT_OFFLINE_LOGSTORAGE_CONFIG_DIR_PATH_LEN] = {0}; - unsigned int num_log_files = 0; - struct stat s; - DltLogStorageFileList **tmp = NULL; - DltLogStorageFileList **newest = NULL; - char file_name[PATH_MAX + 1] = {0}; - - if (config == NULL) - return -1; - - sprintf(storage_path, "%s/", dev_path); - - /* check if there are already files stored */ - if (config->records == NULL) - { - if (dlt_logstorage_storage_dir_info(file_config, storage_path, config) != 0) - return -1; - } - - /* obtain locations of newest, current file names, file count */ - tmp = &config->records; - while(*(tmp) != NULL) - { - num_log_files += 1; - if((*tmp)->next == NULL) - newest = tmp; - - tmp = &(*tmp)->next; - } - - /* need new file*/ - if (num_log_files == 0) - { - dlt_logstorage_log_file_name(file_name, file_config, config->file_name, 1); - - /* concatenate path and file and open absolute path */ - strcat(absolute_file_path, storage_path); - strcat(absolute_file_path, file_name); - config->log = fopen(absolute_file_path, "a+"); - - /* Add file to file list */ - *tmp = malloc(sizeof(DltLogStorageFileList)); - if (*tmp == NULL) - { - dlt_log(LOG_ERR, "Memory allocation failure while adding file name to file list \n"); - return -1; - } - (*tmp)->name = strdup(file_name); - (*tmp)->idx = 1; - (*tmp)->next = NULL; - } - else /* newest file available*/ - { - strcat(absolute_file_path, storage_path); - strcat(absolute_file_path, (*newest)->name); - - ret = stat(absolute_file_path, &s); - - /* if size is enough, open it */ - if (ret == 0 && s.st_size + msg_size < (int)config->file_size) - { - config->log = fopen(absolute_file_path, "a+"); - } - else /* no space in file or file stats cannot be read */ - { - unsigned int idx = 0; - - /* get index of newest log file */ - idx = dlt_logstorage_get_idx_of_log_file(file_config, (*newest)->name); - idx += 1; - - /* wrap around if max index is reached or an error occured - * while calculating index from file name */ - if (idx > file_config.logfile_maxcounter || idx == 0) - idx = 1; - - dlt_logstorage_log_file_name(file_name, file_config, config->file_name, idx); - - /* concatenate path and file and open absolute path */ - memset(absolute_file_path, 0, sizeof(absolute_file_path)/sizeof(char)); - strcat(absolute_file_path, storage_path); - strcat(absolute_file_path, file_name); - config->log = fopen(absolute_file_path, "a+"); - - /* Add file to file list */ - *tmp = malloc(sizeof(DltLogStorageFileList)); - if (*tmp == NULL) - { - dlt_log(LOG_ERR, "Memory allocation failure while adding file name to file list \n"); - return -1; - } - (*tmp)->name = strdup(file_name); - (*tmp)->idx = idx; - (*tmp)->next = NULL; - - num_log_files += 1; - - /* check if number of log files exceeds configured max value */ - if (num_log_files > config->num_files) - { - /* delete oldest */ - DltLogStorageFileList **head = &config->records; - DltLogStorageFileList *n = *head; - memset(absolute_file_path, 0, sizeof(absolute_file_path)/sizeof(char)); - strcat(absolute_file_path, storage_path); - strcat(absolute_file_path, (*head)->name); - remove(absolute_file_path); - free((*head)->name); - *head = n->next; - n->next = NULL; - free(n); - } - } - } - - if (config->log == NULL) - { - dlt_log(LOG_ERR, "dlt_logstorage_create_log_file: Unable to open log file.\n"); - return -1; - } - - return ret; -} - -/** - * dlt_logstorage_prepare_log_file - * - * Prepare the log file for a certain filer. If log file not open or log files max size reached, - * open a new file. - * - * @param config DltLogStorageConfigData - * @param file_config User configurations for log file - * @param dev_path Storage device path - * @param log_msg_size Size of log message - * @return 0 on success, -1 on error - */ -int dlt_logstorage_prepare_log_file(DltLogStorageConfigData *config, - DltLogStorageUserConfig file_config, - char *dev_path, int log_msg_size) -{ - int ret = 0; - struct stat s; - - if (config == NULL) - { - return -1; - } - - if (config->log == NULL) /* open a new log file */ - { - ret = dlt_logstorage_open_log_file(config, file_config, dev_path, log_msg_size); - } - else /* already open, check size and create a new file if needed */ - { - ret = fstat(fileno(config->log), &s); - if (ret == 0) { - /* check if adding new data do not exceed max file size */ - if (s.st_size + log_msg_size >= (int)config->file_size) - { - fclose(config->log); - config->log = NULL; - ret = dlt_logstorage_open_log_file(config, file_config, dev_path, log_msg_size); - } - else /*everything is prepared */ - { - ret = 0; - } - } - else - { - dlt_log(LOG_ERR, "dlt_logstorage_prepare_log_file: Unable to determine file stats.\n"); - ret = -1; - } - } - return ret; -} - -/** * dlt_logstorage_write * * Write a message to one or more configured log files, based on filter configuration. @@ -1582,7 +1220,8 @@ int dlt_logstorage_write(DltLogStorage *handle, DltLogStorageUserConfig file_con return 0; } - /* check if log message need to be stored in a certain device based on filter config */ + /* check if log message need to be stored in a certain device based on + * filter configuration */ config = dlt_logstorage_filter(handle, appid, ctxid, log_level, &num); if (config != NULL) @@ -1593,39 +1232,48 @@ int dlt_logstorage_write(DltLogStorage *handle, DltLogStorageUserConfig file_con if(config[i] != NULL) { /* prepare logfile (create and/or open)*/ - ret = dlt_logstorage_prepare_log_file(config[i], file_config, - handle->device_mount_point, - size1 + size2 + size3); + ret = config[i]->dlt_logstorage_prepare(config[i], + &file_config, + handle->device_mount_point, + size1 + size2 + size3); if (ret == 0) /* log data (write) */ { - fwrite(data1, 1, size1, config[i]->log); - fwrite(data2, 1, size2, config[i]->log); - fwrite(data3, 1, size3, config[i]->log); - ret = ferror(config[i]->log); - - if (ret != 0) + ret = config[i]->dlt_logstorage_write(config[i], + data1, + size1, + data2, + size2, + data3, + size3); + + if (ret == 0) { - handle->write_errors += 1; - if (handle->write_errors >= DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS) + /* flush to be sure log is stored on device */ + ret = config[i]->dlt_logstorage_sync(config[i], + DLT_LOGSTORAGE_SYNC_ON_MSG); + if (ret != 0) { - err = -1; + dlt_log(LOG_ERR, + "dlt_logstorage_write: Unable to sync.\n"); } - - dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to write log to file.\n"); } else { - /* flush to be sure log is stored on device */ - ret = fflush(config[i]->log); - if (ret != 0) + handle->write_errors += 1; + if (handle->write_errors >= + DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS) { - dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to flush log to file.\n"); + err = -1; } + + dlt_log(LOG_ERR, + "dlt_logstorage_write: Unable to write.\n"); } } else { - dlt_log(LOG_ERR, "dlt_logstorage_write: Unable to prepare log file.\n"); + dlt_log(LOG_ERR, + "dlt_logstorage_write: Unable to prepare.\n"); } } i++; diff --git a/src/offlinelogstorage/dlt_offline_logstorage.h b/src/offlinelogstorage/dlt_offline_logstorage.h index 80a75e8..01427a1 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage.h +++ b/src/offlinelogstorage/dlt_offline_logstorage.h @@ -81,16 +81,18 @@ DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + 1) #define DLT_OFFLINE_LOGSTORAGE_FILTER_UNINIT 0 -#define DLT_OFFLINE_LOGSTORAGE_FILTER_PRESENT (1<<6) -#define DLT_OFFLINE_LOGSTORAGE_APP_INIT (1<<5) -#define DLT_OFFLINE_LOGSTORAGE_CTX_INIT (1<<4) -#define DLT_OFFLINE_LOGSTORAGE_LOG_LVL_INIT (1<<3) -#define DLT_OFFLINE_LOGSTORAGE_NAME_INIT (1<<2) -#define DLT_OFFLINE_LOGSTORAGE_SIZE_INIT (1<<1) +#define DLT_OFFLINE_LOGSTORAGE_FILTER_PRESENT (1<<7) +#define DLT_OFFLINE_LOGSTORAGE_APP_INIT (1<<6) +#define DLT_OFFLINE_LOGSTORAGE_CTX_INIT (1<<5) +#define DLT_OFFLINE_LOGSTORAGE_LOG_LVL_INIT (1<<4) +#define DLT_OFFLINE_LOGSTORAGE_NAME_INIT (1<<3) +#define DLT_OFFLINE_LOGSTORAGE_SIZE_INIT (1<<2) +#define DLT_OFFLINE_LOGSTORAGE_SYNC_BEHAVIOR (1<<1) #define DLT_OFFLINE_LOGSTORAGE_NUM_INIT 1 -#define DLT_OFFLINE_LOGSTORAGE_FILTER_INIT 0x7F +/* Sync behavior is optional */ +#define DLT_OFFLINE_LOGSTORAGE_FILTER_INIT 0xFD -#define DLT_OFFLINE_LOGSTORAGE_FILTER_INITIALIZED(A) ((A) == DLT_OFFLINE_LOGSTORAGE_FILTER_INIT) +#define DLT_OFFLINE_LOGSTORAGE_FILTER_INITIALIZED(A) ((A) >= DLT_OFFLINE_LOGSTORAGE_FILTER_INIT) #define DLT_OFFLINE_LOGSTORAGE_IS_FILTER_PRESENT(A) ((A) & DLT_OFFLINE_LOGSTORAGE_FILTER_PRESENT) @@ -105,10 +107,26 @@ #define DLT_OFFLINE_LOGSTORAGE_MIN(A, B) ((A) < (B) ? (A) : (B)) #define DLT_OFFLINE_LOGSTORAGE_MAX_WRITE_ERRORS 5 -#define DLT_OFFLINE_LOGSTORAGE_MAX_KEY_NUM 6 +#define DLT_OFFLINE_LOGSTORAGE_MAX_KEY_NUM 7 #define DLT_OFFLINE_LOGSTORAGE_CONFIG_SECTION "FILTER" +/* Offline Logstorage sync strategies */ +#define DLT_LOGSTORAGE_SYNC_ON_MSG 0x00 /* default, on message sync */ +#define DLT_LOGSTORAGE_SYNC_ON_DAEMON_EXIT 0x01 /* sync on daemon exit */ + + +/* logstorage max cache */ +unsigned int g_logstorage_cache_max; +/* current logstorage cache size */ +unsigned int g_logstorage_cache_size; + +typedef struct +{ + int offset; /* current write offset */ + unsigned int wrap_around_cnt; /* wrap around counter */ +}DltLogStorageCacheFooter; + typedef struct { /* File name user configurations */ @@ -126,14 +144,33 @@ typedef struct DltLogStorageFileList struct DltLogStorageFileList *next; }DltLogStorageFileList; -typedef struct +typedef struct DltLogStorageConfigData DltLogStorageConfigData; + +typedef struct DltLogStorageConfigData { /* filter section */ int log_level; /* Log level number configured for filter */ char *file_name; /* File name for log storage configured for filter */ unsigned int file_size; /* MAX File size of storage file configured for filter */ unsigned int num_files; /* MAX number of storage files configured for filters */ + int sync; /* Sync strategy */ + /* callback function for filter configurations */ + int (*dlt_logstorage_prepare)(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size); + int (*dlt_logstorage_write)(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3); + /* status is strategy, e.g. DLT_LOGSTORAGE_SYNC_ON_MSG is used when callback + * is called on message received */ + int (*dlt_logstorage_sync)(DltLogStorageConfigData *config, int status); FILE *log; /* current open log file */ + void *cache; /* log data cache */ DltLogStorageFileList *records; /* File name list */ }DltLogStorageConfigData; diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior.c b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c new file mode 100644 index 0000000..77823ee --- /dev/null +++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c @@ -0,0 +1,868 @@ +/** + * @licence app begin@ + * Copyright (C) 2015 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * DLT offline log storage functionality source file. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * \author Syed Hameed <shameed@jp.adit-jv.com> ADIT 2015 + * + * \file: dlt_offline_logstorage_behavior.c + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +#include <syslog.h> +#include <limits.h> +#include <dirent.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> + +#include "dlt_offline_logstorage.h" +#include "dlt_offline_logstorage_behavior.h" + +/** + * dlt_logstorage_log_file_name + * + * Create log file name in the form configured by the user + * <filename><delimiter><index><delimiter><timestamp>.dlt + * + * filename: given in configuration file + * delimiter: Punctuation characters (configured in dlt.conf) + * timestamp: yyyy-mm-dd-hh-mm-ss (enabled/disabled in dlt.conf) + * index: Index len depends on wrap around value in dlt.conf + * ex: wrap around = 99, index will 01..99 + * + * @param log_file_name contains complete logfile name + * @param file_config User configurations for log file + * @param name file name given in configuration file + * @param idx continous index of log files + * @ return None + */ +void dlt_logstorage_log_file_name(char *log_file_name, + DltLogStorageUserConfig *file_config, + char *name, + int idx) +{ + if (log_file_name == NULL || file_config == NULL) + { + return; + } + + char file_index[10] = {'\0'}; + + // create log file name + memset(log_file_name, 0, DLT_MOUNT_PATH_MAX * sizeof(char)); + strcat(log_file_name, name); + strncat(log_file_name, &file_config->logfile_delimiter, 1); + + snprintf(file_index, 10, "%d",idx); + if (file_config->logfile_maxcounter != UINT_MAX) + { + /* Setup 0's to be appended in file index until max index len*/ + unsigned int digit_idx = 0; + unsigned int i = 0; + snprintf(file_index, 10, "%d",idx); + digit_idx = strlen(file_index); + for(i=0; i<(file_config->logfile_counteridxlen - digit_idx); i++) + { + strcat(log_file_name, "0"); + } + } + + strcat(log_file_name, file_index); + + /* Add time stamp if user has configured */ + if (file_config->logfile_timestamp) + { + char stamp[DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + 1] = {0}; + time_t t = time(NULL); + struct tm *tm_info = localtime(&t); + sprintf(stamp, + "%c%04d%02d%02d-%02d%02d%02d", + file_config->logfile_delimiter, + 1900 + tm_info->tm_year, + 1 + tm_info->tm_mon, + tm_info->tm_mday, + tm_info->tm_hour, + tm_info->tm_min, + tm_info->tm_sec); + strcat(log_file_name, stamp); + } + + strcat(log_file_name, ".dlt"); +} + +/** + * dlt_logstorage_sort_file_name + * + * Sort the filenames with index based ascending order (bubble sort) + * + * @param head Log filename list + * @ return None + */ +void dlt_logstorage_sort_file_name(DltLogStorageFileList **head) +{ + int done = 0; + + if (head == NULL || *head == NULL || (*head)->next == NULL) + { + return; + } + + while (!done) + { + /* "source" of the pointer to the current node in the list struct */ + DltLogStorageFileList **pv = head; + DltLogStorageFileList *nd = *head; /* local iterator pointer */ + DltLogStorageFileList *nx = (*head)->next; /* local next pointer */ + + done = 1; + + while (nx) + { + if (nd->idx > nx->idx) + { + nd->next = nx->next; + nx->next = nd; + *pv = nx; + + done = 0; + } + pv = &nd->next; + nd = nx; + nx = nx->next; + } + } +} + +/** + * dlt_logstorage_rearrange_file_name + * + * Rearrange the filenames in the order of latest and oldest + * + * @param head Log filename list + * @ return None + */ +void dlt_logstorage_rearrange_file_name(DltLogStorageFileList **head) +{ + DltLogStorageFileList *n_prev = NULL; + DltLogStorageFileList *tail = NULL; + DltLogStorageFileList *wrap_pre = NULL; + DltLogStorageFileList *wrap_post = NULL; + DltLogStorageFileList *n = NULL; + + if (head == NULL || *head == NULL || (*head)->next == NULL) + { + return; + } + + for (n = *head; n != NULL; n = n->next) + { + if (n && n_prev) + { + if ((n->idx - n_prev->idx) != 1) + { + wrap_post = n; + wrap_pre = n_prev; + } + } + n_prev = n; + } + tail = n_prev; + + if (wrap_post && wrap_pre) + { + wrap_pre->next = NULL; + tail->next = *head; + *head = wrap_post; + } +} + +/** + * dlt_logstorage_get_idx_of_log_file + * + * Extract index of log file name passed as input argument + * + * @param file file name to extract the index from + * @param file_config User configurations for log file + * @return index on success, -1 if no index is found + */ +unsigned int dlt_logstorage_get_idx_of_log_file( + DltLogStorageUserConfig *file_config, + char *file) +{ + unsigned int idx = -1; + char *endptr; + char *filename; + unsigned int filename_len = 0 ; + unsigned int fileindex_len = 0; + + if (file_config == NULL || file == NULL) + { + return -1; + } + + /* Calculate actual file name length */ + filename=strchr(file, file_config->logfile_delimiter); + filename_len = strlen(file) - strlen(filename); + + /* index is retrived from file name */ + if(file_config->logfile_timestamp) + { + fileindex_len = strlen(file) - + (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + + DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN + + filename_len + 1); + + idx = (int) strtol(&file[strlen(file) - + (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + + fileindex_len + + DLT_OFFLINE_LOGSTORAGE_TIMESTAMP_LEN)], + &endptr, + 10); + } + else + { + fileindex_len = strlen(file) - + (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + + filename_len + 1); + + idx = (int) strtol(&file[strlen(file)- + (DLT_OFFLINE_LOGSTORAGE_FILE_EXTENSION_LEN + +fileindex_len)], &endptr, 10); + } + + if (endptr == file || idx == 0) + { + dlt_log(LOG_ERR, + "Unable to calculate index from log file name. Reset to 001.\n"); + } + + return idx; +} + +/** + * dlt_logstorage_storage_dir_info + * + * Read file names of storage directory. + * Update the file list, arrange it in order of latest and oldest + * + * @param file_config User configurations for log file + * @param path Path to storage directory + * @param config DltLogStorageConfigData + * @return 0 on success, -1 on error + */ +int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config, + char *path, + DltLogStorageConfigData *config) +{ + int i = 0; + int cnt = 0; + int ret = 0; + struct dirent **files = {0}; + unsigned int current_idx = 0; + + if (config == NULL || + file_config == NULL || + path == NULL || + config->file_name == NULL) + { + return -1; + } + + cnt = scandir(path, &files, 0, alphasort); + if (cnt < 0) + { + dlt_log(LOG_ERR, + "dlt_logstorage_storage_dir_info: Failed to scan directory\n"); + return -1; + } + + for (i = 0; i < cnt; i++) + { + int len = 0; + len = strlen(config->file_name); + if ((strncmp(files[i]->d_name, + config->file_name, + len) == 0) && + (files[i]->d_name[len] == file_config->logfile_delimiter)) + { + DltLogStorageFileList **tmp = NULL; + current_idx = dlt_logstorage_get_idx_of_log_file(file_config, + files[i]->d_name); + + if(config->records == NULL) + { + config->records = malloc(sizeof(DltLogStorageFileList)); + if (config->records == NULL) + { + ret = -1; + dlt_log(LOG_ERR, + "Memory allocation failed\n"); + break; + } + tmp = &config->records; + } + else + { + tmp = &config->records; + while(*(tmp) != NULL) + { + tmp = &(*tmp)->next; + } + *tmp = malloc(sizeof(DltLogStorageFileList)); + if (*tmp == NULL) + { + ret = -1; + dlt_log(LOG_ERR, + "Memory allocation failed\n"); + break; + } + } + (*tmp)->name = strdup(files[i]->d_name); + (*tmp)->idx = current_idx; + (*tmp)->next = NULL; + } + } + + if (ret == 0) + { + dlt_logstorage_sort_file_name(&config->records); + dlt_logstorage_rearrange_file_name(&config->records); + } + + /* free scandir result */ + for (i = 0; i < cnt; i++) + { + free(files[i]); + } + free(files); + + return ret; +} + +/** + * dlt_logstorage_open_log_file + * + * Open a log file. Check storage directory for already created files and open + * the oldest if there is enough space to store at least msg_size. + * Otherwise create a new file, but take configured max number of files into + * account and remove the oldest file if needed. + * + * @param config DltLogStorageConfigData + * @param file_config User configurations for log file + * @param dev_path Storage device path + * @param msg_size Size of incoming message + * @return 0 on succes, -1 on error + */ +int dlt_logstorage_open_log_file(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int msg_size) +{ + int ret = 0; + char absolute_file_path[DLT_MOUNT_PATH_MAX + 1] = {'\0'}; + char storage_path[DLT_OFFLINE_LOGSTORAGE_CONFIG_DIR_PATH_LEN] = {'\0'}; + unsigned int num_log_files = 0; + struct stat s; + DltLogStorageFileList **tmp = NULL; + DltLogStorageFileList **newest = NULL; + char file_name[DLT_MOUNT_PATH_MAX + 1] = {'\0'}; + + if (config == NULL) + { + return -1; + } + + sprintf(storage_path, "%s/", dev_path); + + /* check if there are already files stored */ + if (config->records == NULL) + { + if (dlt_logstorage_storage_dir_info(file_config, storage_path, config) + != 0) + return -1; + } + + /* obtain locations of newest, current file names, file count */ + tmp = &config->records; + while(*(tmp) != NULL) + { + num_log_files += 1; + if((*tmp)->next == NULL) + newest = tmp; + + tmp = &(*tmp)->next; + } + + /* need new file*/ + if (num_log_files == 0) + { + dlt_logstorage_log_file_name(file_name, + file_config, + config->file_name, + 1); + + /* concatenate path and file and open absolute path */ + strcat(absolute_file_path, storage_path); + strcat(absolute_file_path, file_name); + config->log = fopen(absolute_file_path, "a+"); + + /* Add file to file list */ + *tmp = malloc(sizeof(DltLogStorageFileList)); + if (*tmp == NULL) + { + dlt_log(LOG_ERR, + "Memory allocation for file name failed\n"); + return -1; + } + (*tmp)->name = strdup(file_name); + (*tmp)->idx = 1; + (*tmp)->next = NULL; + } + else /* newest file available*/ + { + strcat(absolute_file_path, storage_path); + strcat(absolute_file_path, (*newest)->name); + + ret = stat(absolute_file_path, &s); + + /* if size is enough, open it */ + if (ret == 0 && s.st_size + msg_size < (int)config->file_size) + { + config->log = fopen(absolute_file_path, "a+"); + } + else /* no space in file or file stats cannot be read */ + { + unsigned int idx = 0; + + /* get index of newest log file */ + idx = dlt_logstorage_get_idx_of_log_file(file_config, + (*newest)->name); + idx += 1; + + /* wrap around if max index is reached or an error occurred + * while calculating index from file name */ + if (idx > file_config->logfile_maxcounter || idx == 0) + { + idx = 1; + } + + dlt_logstorage_log_file_name(file_name, + file_config, + config->file_name, + idx); + + /* concatenate path and file and open absolute path */ + memset(absolute_file_path, + 0, + sizeof(absolute_file_path)/sizeof(char)); + strcat(absolute_file_path, storage_path); + strcat(absolute_file_path, file_name); + config->log = fopen(absolute_file_path, "a+"); + + /* Add file to file list */ + *tmp = malloc(sizeof(DltLogStorageFileList)); + if (*tmp == NULL) + { + dlt_log(LOG_ERR, + "Memory allocation for file name failed\n"); + return -1; + } + + (*tmp)->name = strdup(file_name); + (*tmp)->idx = idx; + (*tmp)->next = NULL; + + num_log_files += 1; + + /* check if number of log files exceeds configured max value */ + if (num_log_files > config->num_files) + { + /* delete oldest */ + DltLogStorageFileList **head = &config->records; + DltLogStorageFileList *n = *head; + memset(absolute_file_path, + 0, + sizeof(absolute_file_path)/sizeof(char)); + strcat(absolute_file_path, storage_path); + strcat(absolute_file_path, (*head)->name); + remove(absolute_file_path); + free((*head)->name); + *head = n->next; + n->next = NULL; + free(n); + } + } + } + + if (config->log == NULL) + { + dlt_log(LOG_ERR, + "dlt_logstorage_create_log_file: Unable to open log file.\n"); + return -1; + } + + return ret; +} + +/** + * dlt_logstorage_prepare_on_msg + * + * Prepare the log file for a certain filer. If log file not open or log + * files max size reached, open a new file. + * + * @param config DltLogStorageConfigData + * @param file_config User configurations for log file + * @param dev_path Storage device path + * @param log_msg_size Size of log message + * @return 0 on success, -1 on error + */ +int dlt_logstorage_prepare_on_msg(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size) +{ + int ret = 0; + struct stat s; + + if (config == NULL || file_config == NULL || dev_path == NULL) + { + return -1; + } + + if (config->log == NULL) /* open a new log file */ + { + ret = dlt_logstorage_open_log_file(config, + file_config, + dev_path, + log_msg_size); + } + else /* already open, check size and create a new file if needed */ + { + ret = fstat(fileno(config->log), &s); + if (ret == 0) { + /* check if adding new data do not exceed max file size */ + if (s.st_size + log_msg_size >= (int)config->file_size) + { + fclose(config->log); + config->log = NULL; + ret = dlt_logstorage_open_log_file(config, + file_config, + dev_path, + log_msg_size); + } + else /*everything is prepared */ + { + ret = 0; + } + } + else + { + dlt_log(LOG_ERR, + "dlt_logstorage_prepare_log_file: stat() failed.\n"); + ret = -1; + } + } + return ret; +} + +/** + * dlt_logstorage_write_on_msg + * + * Write the log message. + * + * @param config DltLogStorageConfigData + * @param data1 header + * @param size1 header size + * @param data2 storage header + * @param size2 storage header size + * @param data3 payload + * @param size3 payload size + * @return 0 on success, -1 on error + */ +int dlt_logstorage_write_on_msg(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3) +{ + int ret; + + if (config == NULL || data1 == NULL || data2 == NULL || data3 == NULL) + { + return -1; + } + + ret = fwrite(data1, 1, size1, config->log); + if (ret != size1) + { + dlt_log(LOG_WARNING, "Wrote less data than specified\n"); + } + ret = fwrite(data2, 1, size2, config->log); + if (ret != size2) + { + dlt_log(LOG_WARNING, "Wrote less data than specified\n"); + } + ret = fwrite(data3, 1, size3, config->log); + if (ret != size3) + { + dlt_log(LOG_WARNING, "Wrote less data than specified\n"); + } + + return ferror(config->log); +} + +/** + * dlt_logstorage_sync_on_msg + * + * sync data to disk. + * + * @param config DltLogStorageConfigData + * @param status Strategy flag + * @return 0 on success, -1 on error + */ +int dlt_logstorage_sync_on_msg(DltLogStorageConfigData *config, int status) +{ + int ret; + + if (config == NULL) + { + return -1; + } + + if (status == DLT_LOGSTORAGE_SYNC_ON_MSG) /* sync on every message */ + { + ret = fflush(config->log); + + if (ret != 0) + { + dlt_log(LOG_ERR, "fflush failed\n"); + } + } + + return 0; +} + +/** + * dlt_logstorage_prepare_on_daemon_exit + * + * Prepare the log file for a certain filer. If log file not open or log + * files max size reached, open a new file. + * Create a memory area to cache data. + * + * @param config DltLogStorageConfigData + * @param file_config User configurations for log file + * @param dev_path Storage device path + * @param log_msg_size Size of log message + * @return 0 on success, -1 on error + */ +int dlt_logstorage_prepare_on_daemon_exit(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size) +{ + if (config == NULL || file_config == NULL || dev_path == NULL) + { + return -1; + } + + log_msg_size = log_msg_size; /* satisfy compiler */ + + /* open log file */ + if (config->cache == NULL) + { + /* get always a new file */ + if (dlt_logstorage_prepare_on_msg(config, + file_config, + dev_path, + config->file_size) != 0) + { + dlt_log(LOG_ERR, + "Cannot prepare log file for ON_DAEMON_EXIT sync\n"); + return -1; + } + + /* check total logstorage cache size */ + if ((g_logstorage_cache_size + + config->file_size + + sizeof(DltLogStorageCacheFooter)) > + g_logstorage_cache_max) + { + dlt_log(LOG_ERR, "Max size of Logstorage Cache already used."); + return -1; + } + + config->cache = calloc(1, + config->file_size + + sizeof(DltLogStorageCacheFooter)); + + /* update current used cache size */ + g_logstorage_cache_size = config->file_size + + sizeof(DltLogStorageCacheFooter); + + if (config->cache == NULL) + { + dlt_log(LOG_CRIT, + "Cannot allocate memory for filter ring buffer\n"); + } + } + + return 0; +} + +/** + * dlt_logstorage_write_on_daemon_exit + * + * Write the log message. + * + * @param config DltLogStorageConfigData + * @param data1 header + * @param size1 header size + * @param data2 storage header + * @param size2 storage header size + * @param data3 payload + * @param size3 payload size + * @return 0 on success, -1 on error + */ +int dlt_logstorage_write_on_daemon_exit(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3) +{ + DltLogStorageCacheFooter *footer = NULL; + int msg_size; + int remain_cache_size; + void *curr_write_addr = NULL; + + if (config == NULL || data1 == NULL || size1 < 0 || data2 == NULL || + size2 < 0 || data3 == NULL || size3 < 0 || config->cache == NULL) + { + return -1; + } + + footer = (DltLogStorageCacheFooter *)(config->cache + config->file_size); + if (footer == NULL) + { + dlt_log(LOG_ERR, "Cannot retrieve cache footer. Address is NULL\n"); + return -1; + } + + msg_size = size1 + size2 + size3; + remain_cache_size = config->file_size - footer->offset; + + if (msg_size < remain_cache_size) /* add at current position */ + { + curr_write_addr = (void *)(config->cache + footer->offset); + footer->offset += msg_size; + } + else if (msg_size > remain_cache_size) + { + if ((unsigned int) msg_size > config->file_size) + { + dlt_log(LOG_WARNING, "Message is larger than cache. Discard.\n"); + return -1; + } + + /* start writing from beginning */ + curr_write_addr = config->cache; + footer->offset = msg_size; + footer->wrap_around_cnt += 1; + } + else /* message just fits into cache */ + { + curr_write_addr = (void *)(config->cache + footer->offset); + footer->offset = 0; + footer->wrap_around_cnt += 1; + } + + /* write data to cache */ + memcpy(curr_write_addr, data1, size1); + curr_write_addr += size1; + memcpy(curr_write_addr, data2, size2); + curr_write_addr += size2; + memcpy(curr_write_addr, data3, size3); + + return 0; +} + +/** + * dlt_logstorage_sync_on_daemon_exit + * + * sync data to disk. + * + * @param config DltLogStorageConfigData + * @param status Strategy flag + * @return 0 on success, -1 on error + */ +int dlt_logstorage_sync_on_daemon_exit(DltLogStorageConfigData *config, + int status) +{ + int ret = 0; + DltLogStorageCacheFooter *footer = NULL; + + if (config == NULL) + { + return -1; + } + + if (status == config->sync) /* only sync on exit */ + { + if (config->log == NULL || config->cache == NULL) + { + dlt_log(LOG_ERR, + "Cannot copy cache to file. One of both is NULL\n"); + return -1; + } + + /* TODO: write only what is needed */ + /* write ring buffer into file */ + footer = (DltLogStorageCacheFooter *)(config->cache + + config->file_size); + + if (footer == NULL) + { + dlt_log(LOG_ERR, "Cannot retrieve cache information\n"); + return -1; + } + + /* TODO: check if really the whole cache need to be written */ + /* write cache to file */ + ret = fwrite(config->cache, config->file_size, 1, config->log); + + if (ret <= 0) + { + if (ferror(config->log) != 0) + { + dlt_log(LOG_CRIT, "Failed to write cache into log file\n"); + } + } + else + { + /* force sync */ + if (fsync(fileno(config->log)) != 0) + { + dlt_log(LOG_ERR, "Failed to sync log file\n"); + } + } + } + + return ret; +} diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior.h b/src/offlinelogstorage/dlt_offline_logstorage_behavior.h new file mode 100644 index 0000000..16394be --- /dev/null +++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior.h @@ -0,0 +1,91 @@ +/** + * @licence app begin@ + * Copyright (C) 2015 Advanced Driver Information Technology. + * This code is developed by Advanced Driver Information Technology. + * Copyright of Advanced Driver Information Technology, Bosch and DENSO. + * + * DLT offline log storage functionality header file. + * + * \copyright + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with + * this file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * \author Christoph Lipka <clipka@jp.adit-jv.com> ADIT 2015 + * + * \file: dlt_offline_logstorage_behavior.h + * For further information see http://www.genivi.org/. + * @licence end@ + */ + +/******************************************************************************* +** ** +** SRC-MODULE: dlt_offline_logstorage_behavior.h ** +** ** +** TARGET : linux ** +** ** +** PROJECT : DLT ** +** ** +** AUTHOR : Christoph Lipka clipka@jp.adit-jv.com ** +** ** +** PURPOSE : ** +** ** +** REMARKS : ** +** ** +** PLATFORM DEPENDANT [yes/no]: yes ** +** ** +** TO BE CHANGED BY USER [yes/no]: no ** +** ** +*******************************************************************************/ + +/******************************************************************************* +** Author Identity ** +******************************************************************************** +** ** +** Initials Name Company ** +** -------- ------------------------- ---------------------------------- ** +** cl Christoph Lipka ADIT ** +*******************************************************************************/ + + +#ifndef DLT_OFFLINELOGSTORAGE_DLT_OFFLINE_LOGSTORAGE_BEHAVIOR_H_ +#define DLT_OFFLINELOGSTORAGE_DLT_OFFLINE_LOGSTORAGE_BEHAVIOR_H_ + +/* ON_MSG behavior */ +int dlt_logstorage_prepare_on_msg(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size); +int dlt_logstorage_write_on_msg(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3); + +/* status is strategy, e.g. DLT_LOGSTORAGE_SYNC_ON_MSG is used when callback + * is called on message received */ +int dlt_logstorage_sync_on_msg(DltLogStorageConfigData *config, int status); + +/* ON_DAEMON_EXIT behavior */ +int dlt_logstorage_prepare_on_daemon_exit(DltLogStorageConfigData *config, + DltLogStorageUserConfig *file_config, + char *dev_path, + int log_msg_size); + +int dlt_logstorage_write_on_daemon_exit(DltLogStorageConfigData *config, + unsigned char *data1, + int size1, + unsigned char *data2, + int size2, + unsigned char *data3, + int size3); + +/* status is strategy, e.g. DLT_LOGSTORAGE_SYNC_ON_MSG is used when callback + * is called on message received */ +int dlt_logstorage_sync_on_daemon_exit(DltLogStorageConfigData *config, + int status); + +#endif /* DLT_OFFLINELOGSTORAGE_DLT_OFFLINE_LOGSTORAGE_BEHAVIOR_H_ */ |