279e7f51f4b31ef5225c73969280c7c1a47ebcb6
[platform/core/appfw/app-installers.git] / src / common / utils / file_logbackend.cc
1 // Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/utils/file_logbackend.h"
6
7 #include <manifest_parser/utils/logging.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <fstream>
14 #include <memory>
15 #include <sstream>
16 #include <string>
17 #include <utility>
18
19 namespace {
20
21 constexpr mode_t kDefaultMode640 = S_IRUSR | S_IWUSR | S_IRGRP;
22
23 }  // namespace
24
25 namespace utils {
26
27 FileLogBackend::FileLogBackend(std::string file_path, int rotation_size,
28     int max_rotation)
29     : file_path_(std::move(file_path)), rotation_size_(rotation_size),
30       max_rotation_(max_rotation), log_stream_(
31           std::unique_ptr<std::ostringstream>(new std::ostringstream())) {
32 }
33
34
35 void FileLogBackend::WriteLog(LogLevel level, const std::string& /* tag */,
36     const std::string& logstr) {
37   if (level != LogLevel::LOG_DEBUG)
38     *log_stream_ << GetTimeStamp() << GetPid() << logstr << std::endl;
39 }
40
41 void FileLogBackend::WriteLogToFile() {
42   if (file_path_.empty())
43     return;
44
45   int size = GetFileSize(file_path_);
46   if (size > rotation_size_)
47     if (!Rotate())
48       return;
49
50   std::ofstream ofs(file_path_.c_str(), std::ios::app);
51   ofs << log_stream_->str();
52   ofs.close();
53
54   // clean the log stream
55   log_stream_->str("");
56   log_stream_->clear();
57
58   if (chmod(file_path_.c_str(), kDefaultMode640) != 0)
59     LOG(ERROR) << "Failed to set permission on log, errno : " << errno;
60 }
61
62 bool FileLogBackend::Rotate() {
63   std::string logdir = GetLogDir();
64   int dirfd = open(logdir.c_str(), O_DIRECTORY);
65   for (int i = max_rotation_; i > 0; i--) {
66     std::string old_log = GetFileName() + "." + std::to_string(i);
67
68     if (dirfd < 0) {
69       LOG(ERROR) << "Failed to open dir(" << logdir << "), errno : " << errno;
70       return false;
71     }
72     struct stat tmp_buffer;
73     if (fstatat(dirfd, old_log.c_str(), &tmp_buffer, 0) != 0)
74       continue;
75
76     // the oldest log will be removed
77     if (i == max_rotation_) {
78       if (unlinkat(dirfd, old_log.c_str(), 0) != 0) {
79         close(dirfd);
80         return false;
81       }
82     } else {
83       std::string new_log = GetFileName() + "." + std::to_string(i + 1);
84       if (renameat(dirfd, old_log.c_str(), dirfd, new_log.c_str()) != 0) {
85         close(dirfd);
86         return false;
87       }
88     }
89   }
90   std::string new_log = GetFileName() + ".1";
91   if (renameat(dirfd, file_path_.c_str(), dirfd, new_log.c_str()) != 0) {
92     close(dirfd);
93     return false;
94   }
95   close(dirfd);
96
97   return true;
98 }
99
100 int FileLogBackend::GetFileSize(const std::string& file_name) {
101   struct stat sb;
102   int ret = stat(file_name.c_str(), &sb);
103   return ret == 0 ? sb.st_size : -1;
104 }
105
106 std::string FileLogBackend::GetTimeStamp() {
107   struct timespec ts;
108   clock_gettime(CLOCK_REALTIME, &ts);
109
110   time_t seconds = ts.tv_sec;
111   struct tm gmt;
112   if (!gmtime_r(&seconds, &gmt))
113     return "|";
114   int32_t miliseconds = ts.tv_nsec / 1000000;
115
116   char buf[32];
117   strftime(buf, sizeof(buf), "%Y%m%d.%H%M%S", &gmt);
118   char timestamp[32];
119   snprintf(timestamp, sizeof(timestamp), "%s.%03dUTC|", buf, miliseconds);
120
121   return timestamp;
122 }
123
124 std::string FileLogBackend::GetPid() {
125   return std::to_string(getpid()) + "|";
126 }
127
128 std::string FileLogBackend::GetLogDir() {
129   return file_path_.substr(0, file_path_.find_last_of("\\/") + 1);
130 }
131
132 std::string FileLogBackend::GetFileName() {
133   return file_path_.substr(file_path_.find_last_of("\\/") + 1);
134 }
135
136 }  // namespace utils