3 * Copyright (c) 2005-2008, The Android Open Source Project
4 * Copyright (c) 2012-2015 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <queued_entry_timestamp.h>
23 #include <sys/types.h>
30 #define DEFAULT_LOGFILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
33 * @addtogroup SHARED_FUNCTIONS
37 void logfile_init(struct log_file *l_file)
41 memset(l_file, 0, sizeof(struct log_file));
44 l_file->rotate_size_kbytes = DEFAULT_ROTATE_SIZE_KB;
45 l_file->max_rotated = DEFAULT_ROTATE_NUM_FILES;
46 l_file->format.format = FORMAT_BRIEF;
47 l_file->isatty = false;
48 l_file->colors_auto = true;
49 l_file->prev_sec = INT_MIN;
50 l_file->prev_nsec = INT_MIN;
53 static void logfile_set_should_close(struct log_file *l_file, int on_off)
57 assert(l_file->fd >= 0);
59 l_file->should_close = !!on_off;
62 void logfile_set_fd(struct log_file *l_file, int fd, int should_close)
67 l_file->isatty = isatty(fd);
68 logfile_set_should_close(l_file, should_close);
71 int logfile_set_path(struct log_file *l_file, const char *path)
75 char *p = strdup(path);
86 static void logfile_close_if_needed(struct log_file *l_file)
90 if (l_file->fd >= 0 && l_file->should_close) {
92 logfile_set_should_close(l_file, 0);
98 void logfile_free(struct log_file *l_file)
106 logfile_close_if_needed(l_file);
109 static int logfile_update_fsize(struct log_file *l_file)
112 assert(l_file->fd >= 0);
116 if (fstat(l_file->fd, &st) < 0)
119 l_file->size = st.st_size;
123 static int logfile_open_internal(struct log_file *l_file)
126 assert(l_file->path);
128 logfile_close_if_needed(l_file);
130 int fd = open(l_file->path, O_CREAT | O_WRONLY | O_APPEND, DEFAULT_LOGFILE_PERM);
134 logfile_set_fd(l_file, fd, 1);
135 logfile_update_fsize(l_file);
140 void logfile_move(struct log_file *to, struct log_file *from)
149 * @brief Open a log file
150 * @details Open a log file into the passed structure.
151 * @param[in] l_file The file structure to contain the opened file descriptor
152 * @remarks Creates the file if it does not exist, else appends to it.
154 int logfile_open(struct log_file *l_file)
158 int r = logfile_open_internal(l_file);
162 r = logfile_rotate_needed(l_file);
164 logfile_do_rotate(l_file);
170 * @brief Checks if log file should be rotated
171 * @param[in] l_file The file structure to contain the currently opened file
172 * @remarks Updates l_file->size with on-disk file size
173 * @returns 1 if rotate is needed, 0 if not, -errno on error
175 int logfile_rotate_needed(struct log_file *l_file)
179 if (l_file->path == NULL || l_file->rotate_size_kbytes <= 0 || l_file->max_rotated <= 0)
182 logfile_update_fsize(l_file);
183 return BtoKiB(l_file->size) > l_file->rotate_size_kbytes;
187 * @brief Rotate log files
188 * @details Opens a new file and moves existing files further back
189 * @param[in] file The file structure to contain the currently opened file
191 void logfile_do_rotate(struct log_file *file)
197 char path0[PATH_MAX];
198 char path1[PATH_MAX];
200 for (i = file->max_rotated ; i > 0 ; i--) {
201 snprintf(path1, PATH_MAX, "%s.%d", file->path, i);
203 snprintf(path0, PATH_MAX, "%s", file->path);
205 snprintf(path0, PATH_MAX, "%s.%d", file->path, i - 1);
206 if (rename(path0, path1) < 0 && errno != ENOENT)
207 ERR("while rotating log file: %s", file->path);
210 /* open log file again */
211 logfile_open_internal(file);
214 static void logfile_add_timestamp(struct log_file *file, struct timespec ts)
216 file->prev_sec = ts.tv_sec;
217 file->prev_nsec = ts.tv_nsec;
221 * @brief Write with rotation
222 * @details Writes the entry to given file, automatically handling file rotation
223 * @param[in] e The entry to write
224 * @param[in] file The file to write to
225 * @returns 0 if log was successfully written, else 1
227 int logfile_write_with_rotation(const dlogutil_entry_s *e, struct log_file *file, dlogutil_sorting_order_e sort_by)
229 if (file->colors_auto)
230 file->format.color = file->isatty;
232 int written_bytes = 0;
235 if (dlogutil_entry_get_timestamp(e, sort_by, &ts) != TIZEN_ERROR_NONE)
238 if (ts.tv_sec < file->prev_sec || (ts.tv_sec == file->prev_sec && ts.tv_nsec < file->prev_nsec)) {
239 struct dlogutil_entry_with_msg msg;
240 memcpy(&msg, e, sizeof *e);
242 if (dlogutil_entry_get_tag(e, &tag) != TIZEN_ERROR_NONE)
244 int r = snprintf(msg.msg, sizeof msg.msg, "%s%c%s", tag, '\0', "INFO: Following log entry could not be sorted and is out of order.");
247 ERR("unable to format out-of-order message %m");
250 msg.header.len = r + 1 + sizeof *e;
252 written_bytes += log_print_log_line(file->format, file->fd, &msg.header);
254 if (written_bytes < 0) {
255 ERR("unable to write out-of-order message %m");
261 written_bytes += log_print_log_line(file->format, file->fd, e);
262 if (written_bytes <= 0)
264 file->size += written_bytes;
266 logfile_add_timestamp(file, ts);
268 if (logfile_rotate_needed(file))
269 logfile_do_rotate(file);