diff --git a/doc/dlt_offline_logstorage.md b/doc/dlt_offline_logstorage.md index e2346e5b2..67490ffaa 100644 --- a/doc/dlt_offline_logstorage.md +++ b/doc/dlt_offline_logstorage.md @@ -77,7 +77,7 @@ NOFiles= # Number of created files before oldest is SyncBehavior= # Specify sync strategy. Default: Sync'ed after every message. See Logstorage Ringbuffer Implementation below. EcuID= # Specify ECU identifier SpecificSize= # Store logs in storage devices after specific size is reached. -GzipCompression= # Write the logfiles with gzip compression. +GzipCompression= # Write the logfiles with gzip compression. ON: Continously, FILE: On file rotation OverwriteBehavior= # Specify overwrite strategy. Default: Delete oldest file and continue. See Logstorage Ringbuffer Implementation below. DisableNetwork= # Specify if the message shall be routed to network client. ``` diff --git a/src/offlinelogstorage/dlt_offline_logstorage.c b/src/offlinelogstorage/dlt_offline_logstorage.c index 77f8bc223..c6556f30d 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage.c +++ b/src/offlinelogstorage/dlt_offline_logstorage.c @@ -1337,7 +1337,11 @@ DLT_STATIC int dlt_logstorage_check_gzip_compression(DltLogStorageFilterConfig * if (strcasestr(value, "ON") != NULL) { config->gzip_compression = DLT_LOGSTORAGE_GZIP_ON; - } else if (strcasestr(value, "OFF") != NULL) { + } + else if (strcasestr(value, "FILE") != NULL) { + config->gzip_compression = DLT_LOGSTORAGE_GZIP_FILE; + } + else if (strcasestr(value, "OFF") != NULL) { config->gzip_compression = DLT_LOGSTORAGE_GZIP_OFF; } else { dlt_log(LOG_WARNING, "Unknown gzip compression flag\n"); diff --git a/src/offlinelogstorage/dlt_offline_logstorage.h b/src/offlinelogstorage/dlt_offline_logstorage.h index 37b8f857f..21e0a31e9 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage.h +++ b/src/offlinelogstorage/dlt_offline_logstorage.h @@ -123,11 +123,14 @@ #define DLT_LOGSTORAGE_DISABLE_NW_OFF 1 /* default, enable network routing */ #define DLT_LOGSTORAGE_DISABLE_NW_ON (1 << 1) /* disable network routing */ -/* Offline Logstorage disable network routing */ +/* Offline Logstorage enable gzip compression */ #define DLT_LOGSTORAGE_GZIP_ERROR -1 /* error case */ #define DLT_LOGSTORAGE_GZIP_UNSET 0 /* not set */ #define DLT_LOGSTORAGE_GZIP_OFF 1 /* default, no compression */ -#define DLT_LOGSTORAGE_GZIP_ON (1 << 1) /* enable gzip compression */ +#define DLT_LOGSTORAGE_GZIP_ON \ + (1 << 1) /* enable gzip compression of all files */ +#define DLT_LOGSTORAGE_GZIP_FILE \ + (1 << 2) /* enable gzip compression on file rotation */ /* logstorage max cache */ extern unsigned int g_logstorage_cache_max; diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior.c b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c index e705c3ef2..76bc2b6d5 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage_behavior.c +++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior.c @@ -372,7 +372,8 @@ int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config, config->records = NULL; } - char *suffix = config->gzip_compression == DLT_LOGSTORAGE_GZIP_ON ? ".dlt.gz" : ".dlt"; + char *suffix = ".dlt.gz"; + char *gzsuffix = ".dlt"; for (i = 0; i < cnt; i++) { int len = 0; @@ -385,10 +386,13 @@ int dlt_logstorage_storage_dir_info(DltLogStorageUserConfig *file_config, if (config->num_files == 1 && file_config->logfile_optional_counter) { /* .dlt or _.dlt */ if ((files[i]->d_name[len] == suffix[0]) || + (files[i]->d_name[len] == gzsuffix[0]) || (file_config->logfile_timestamp && - (files[i]->d_name[len] == file_config->logfile_delimiter))) { + (files[i]->d_name[len] == + file_config->logfile_delimiter))) { current_idx = 1; - } else { + } + else { continue; } } else { @@ -732,6 +736,29 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config, } } +#ifdef DLT_LOGSTORAGE_USE_GZIP + if (config->gzip_compression == DLT_LOGSTORAGE_GZIP_FILE) { + tmp = &config->records; + while ((*tmp)->next != NULL) { + int len = strlen((*tmp)->name); + const char *suffix = ".dlt"; + if (strcmp(&(*tmp)->name[len - strlen(suffix)], suffix) == + 0) { + memset(absolute_file_path, 0, + sizeof(absolute_file_path) / sizeof(char)); + strcat(absolute_file_path, storage_path); + strncat(absolute_file_path, (*tmp)->name, len); + dlt_vlog(LOG_INFO, + "%s: Compressing '%s' (num_log_files: %d, " + "file_name:%s)\n", + __func__, absolute_file_path, num_log_files, + (*tmp)->name); + dlt_logstorage_compress_dlt_file(absolute_file_path); + } + tmp = &(*tmp)->next; + } + } +#endif } } @@ -761,6 +788,114 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config, return ret; } +#ifdef DLT_LOGSTORAGE_USE_GZIP +/** + * dlt_logstorage_compress_dlt_file + * + * Compress content of a file and remove the original file. + * compressed file name is the same as the original with .gz extension. + * + * @param file_path The file to compress + * @return 0 on success, -1 on error + */ +int dlt_logstorage_compress_dlt_file(char *file_path) +{ + char file_path_dest[DLT_OFFLINE_LOGSTORAGE_MAX_PATH_LEN + 1] = {'\0'}; + strcat(file_path_dest, file_path); + strcat(file_path_dest, ".gz"); + + FILE *source = fopen(file_path, "rb"); + if (source == NULL) { + dlt_vlog(LOG_ERR, "%s: could not open %s\n", __func__, file_path); + return -1; + } + + FILE *dest = fopen(file_path_dest, "wb"); + if (dest == NULL) { + dlt_vlog(LOG_ERR, "%s: could not open %s\n", __func__, file_path_dest); + fclose(source); + return -1; + } + + gzFile gzfile = gzdopen(fileno(dest), "wb"); + if (dest == NULL) { + dlt_vlog(LOG_ERR, "%s: could not gz open %s\n", __func__, + file_path_dest); + fclose(source); + fclose(dest); + return -1; + } + + int ret = dlt_logstorage_compress_fd(source, gzfile); + + fclose(source); + gzclose(gzfile); + fclose(dest); + + if (ret == 0 && remove(file_path) != 0) { + dlt_vlog(LOG_ERR, "%s: could not remove original file %s \n", __func__, + file_path); + return -1; + } + + return ret; +} +#endif + +#ifdef DLT_LOGSTORAGE_USE_GZIP +/** + * dlt_logstorage_compress_fd + * + * Compress content of a file descriptor into a gzFile. + * + * @param source The file to compress + * @param dest The file to write to + * @return 0 on success, -1 on error + */ +int dlt_logstorage_compress_fd(FILE *source, gzFile dest) +{ + int ret, flush; + z_stream strm; + unsigned char in[COMPRESS_CHUNK]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK) + return ret; + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, COMPRESS_CHUNK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + dlt_vlog(LOG_ERR, "%s: Can't open source\n", __func__); + return -1; + } + + ret = gzwrite(dest, in, strm.avail_in); + if (ret == 0) { + (void)deflateEnd(&strm); + dlt_vlog(LOG_ERR, "%s: failed to write to log file\n", __func__); + return -1; + } + if (gzflush(dest, Z_SYNC_FLUSH) != 0) + dlt_vlog(LOG_ERR, "%s: failed to gzflush log file\n", __func__); + + flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + // done when last data in file processed + } while (flush != Z_FINISH); + + // clean up and return + (void)deflateEnd(&strm); + return 0; +} +#endif + /** * dlt_logstorage_find_dlt_header * diff --git a/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h b/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h index ec820d513..f2f6ba58a 100644 --- a/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h +++ b/src/offlinelogstorage/dlt_offline_logstorage_behavior_internal.h @@ -75,6 +75,12 @@ int dlt_logstorage_open_log_file(DltLogStorageFilterConfig *config, bool is_update_required, bool is_sync); +#ifdef DLT_LOGSTORAGE_USE_GZIP +#define COMPRESS_CHUNK 16384 +int dlt_logstorage_compress_dlt_file(char *path); +int dlt_logstorage_compress_fd(FILE *source, gzFile dest); +#endif + DLT_STATIC int dlt_logstorage_sync_to_file(DltLogStorageFilterConfig *config, DltLogStorageUserConfig *file_config, char *dev_path,