135f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// Copyright 2015 The Android Open Source Project 235f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// 335f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// Licensed under the Apache License, Version 2.0 (the "License"); 435f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// you may not use this file except in compliance with the License. 535f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// You may obtain a copy of the License at 635f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// 735f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// http://www.apache.org/licenses/LICENSE-2.0 835f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// 935f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// Unless required by applicable law or agreed to in writing, software 1035f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// distributed under the License is distributed on an "AS IS" BASIS, 1135f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1235f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// See the License for the specific language governing permissions and 1335f6587840b71c8bd3e3655508b6f05cb2593ba9Daniel Erat// limitations under the License. 14c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 15f719c98766c61db6faecde5808c6af26d993ce44Daniel Erat#include "webservd/log_manager.h" 16c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 17c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <arpa/inet.h> 18c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <cinttypes> 19c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <netinet/in.h> 20c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <set> 21c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 22c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <base/bind.h> 23c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <base/files/file_enumerator.h> 24c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <base/files/file_util.h> 25c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <base/lazy_instance.h> 26c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko#include <base/strings/stringprintf.h> 2775d6da24dedcbc090d23de60c4f1637c3a54b392Alex Vakulenko#include <brillo/strings/string_utils.h> 28c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 29c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkonamespace webservd { 30c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 31c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkonamespace { 32c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 33c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// Singleton instance of LogManager class. 34c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkobase::LazyInstance<LogManager> g_log_manager = LAZY_INSTANCE_INITIALIZER; 35c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 36c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// The number of files to keep in the log directory. Since there is one log 37c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// file per day of logging, this is essentially how many days' worth of logs 38c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// to keep. This also controls the total maximum size of the log data, which 39c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// is (kLogFilesToKeep * kMaxLogFileSize). 40c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkoconst size_t kLogFilesToKeep = 7; 41c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 42c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// Maximum log file size. 43c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkoconst int64_t kMaxLogFileSize = 1024 * 1024; // 1 MB 44c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 45c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// Obtain an IP address as a human-readable string for logging. 46c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkostd::string GetIPAddress(const sockaddr* addr) { 47c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko static_assert(INET6_ADDRSTRLEN > INET_ADDRSTRLEN, "Unexpected IP addr len."); 48c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko char buf[INET6_ADDRSTRLEN] = "-"; 49f38547e749b2feee717aa13066000e3cdfd6e183Alex Vakulenko if (!addr) 50f38547e749b2feee717aa13066000e3cdfd6e183Alex Vakulenko return buf; 51f38547e749b2feee717aa13066000e3cdfd6e183Alex Vakulenko 52c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko switch (addr->sa_family) { 53c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko case AF_INET: { 54c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko auto addr_in = reinterpret_cast<const sockaddr_in*>(addr); 55c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (!inet_ntop(AF_INET, &addr_in->sin_addr, buf, sizeof(buf))) 56c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko PLOG(ERROR) << "Unable to get IP address string (IPv4)"; 57c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 58c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko break; 59c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 60c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko case AF_INET6: { 61c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko auto addr_in6 = reinterpret_cast<const sockaddr_in6*>(addr); 62c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 63c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Note that inet_ntop(3) doesn't handle IPv4-mapped IPv6 64c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // addresses [1] the way you'd expect .. for example, it returns 65c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // "::ffff:172.22.72.163" instead of the more traditional IPv4 66c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // notation "172.22.72.163". Fortunately, this is pretty easy to 67c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // fix ourselves. 68c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // 69c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // [1] : see RFC 4291, section 2.5.5.2 for what that means 70c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // http://tools.ietf.org/html/rfc4291#section-2.5.5 71c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // 72c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko auto dwords = reinterpret_cast<const uint32_t*>(&addr_in6->sin6_addr); 73c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (dwords[0] == 0x00000000 && dwords[1] == 0x00000000 && 74c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko dwords[2] == htonl(0x0000ffff)) { 75c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko auto bytes = reinterpret_cast<const uint8_t*>(&addr_in6->sin6_addr); 76c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko return base::StringPrintf("%d.%d.%d.%d", 77c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko bytes[12], bytes[13], bytes[14], bytes[15]); 78c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } else if (!inet_ntop(AF_INET6, &addr_in6->sin6_addr, buf, sizeof(buf))) { 79c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko PLOG(ERROR) << "Unable to get IP address string (IPv6)"; 80c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 81c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 82c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko break; 83c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 84c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko default: 85c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko LOG(ERROR) << "Unsupported address family " << addr->sa_family; 86c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko break; 87c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 88c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko return buf; 89c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} 90c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 91c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} // Anonymous namespace 92c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 93c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko// Logger class to write the log data to a log file. 9415c915985a72d77125746bcdb576bb4fb8d97834Alex Vakulenkoclass FileLogger final : public LogManager::LoggerInterface { 95c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko public: 96c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko FileLogger(const base::FilePath& log_directory, LogManager* log_manager) 97c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko : log_directory_(log_directory), log_manager_{log_manager} {} 98c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 99c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Write the log entry to today's log file. 100c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko void Log(const base::Time& timestamp, const std::string& entry) override { 101c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko tm time_buf = {}; 102c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko char file_name[32] = {}; 103c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Create the file name in year-month-day format so that string sort would 104c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // correspond to date sort. 105c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko time_t time = timestamp.ToTimeT(); 106c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko strftime(file_name, sizeof(file_name), "%Y-%m-%d.log", 107c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko localtime_r(&time, &time_buf)); 108c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FilePath file_path = log_directory_.Append(file_name); 109c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko bool success = false; 110c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko bool exists = base::PathExists(file_path); 111c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // If the file already exists, check its size. If it is going to be larger 112c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // then the maximum allowed log size, archive the current log file and 113c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // create a new, empty one. 114c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (exists) { 115c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko int64_t file_size = 0; 116c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko bool got_size = base::GetFileSize(file_path, &file_size); 117c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (got_size && (file_size + entry.size() > kMaxLogFileSize)) 118c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko exists = !ArchiveLogFile(file_name); 119c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 120c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 121c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (exists) { 122c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko success = base::AppendToFile(file_path, entry.data(), entry.size()); 123c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } else { 124c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko int size = static_cast<int>(entry.size()); 125c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko success = (base::WriteFile(file_path, entry.data(), size) == size); 126c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (success) { 127c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // We just created a new file, see if we need to purge old ones. 128c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko log_manager_->PerformLogMaintenance(); 129c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 130c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 131c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko PLOG_IF(ERROR, !success) << "Failed to append a log entry to log file at " 132c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko << file_path.value(); 133c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 134c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 135c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko private: 136c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Renames the log file to a next available suffix-appended archive when 137c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // the log file size starts to exceed the pre-defined maximum size. 138c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // The existing log file is renamed by changing the original |file_name| to 139c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // YYYY-MM-DD-<suffix>.log where suffix is characters 'a', 'b', ... 140c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Since '-' comes before '.', "2015-02-25-a.log" will come before 141c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // "2015-02-25.log" in sort order and the previously-renamed files will be 142c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // considered "older" than the current one, which is what we need. 143c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Returns true if the file has been successfully renamed. 144c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko bool ArchiveLogFile(const std::string& file_name) { 145c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko char suffix = 'a'; 14675d6da24dedcbc090d23de60c4f1637c3a54b392Alex Vakulenko auto pair = brillo::string_utils::SplitAtFirst(file_name, "."); 147c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // If we try all the suffixes from 'a' to 'z' and still can't find a name, 148c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // abandon this strategy and keep appending to the current file. 149c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko while (suffix <= 'z') { 150c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FilePath archive_file_path = log_directory_.Append( 151c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::StringPrintf("%s-%c.%s", pair.first.c_str(), 152c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko suffix, pair.second.c_str())); 153c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (!base::PathExists(archive_file_path)) { 154c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FilePath file_path = log_directory_.Append(file_name); 155c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko if (base::Move(file_path, archive_file_path)) { 156c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Successfully renamed, start a new log file. 157c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko return true; 158c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } else { 159c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko PLOG(ERROR) << "Failed to rename log file from " 160c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko << file_path.value() << " to " 161c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko << archive_file_path.value(); 162c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 163c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko break; 164c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 165c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko suffix++; 166c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 167c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko return false; 168c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 169c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 170c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FilePath log_directory_; 171c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko LogManager* log_manager_{nullptr}; 172c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko}; 173c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 174c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkovoid LogManager::Init(const base::FilePath& log_directory) { 175c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko LogManager* inst = GetInstance(); 176c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko inst->log_directory_ = log_directory; 177c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko inst->SetLogger( 178c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko std::unique_ptr<LoggerInterface>{new FileLogger{log_directory, inst}}); 179c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko inst->PerformLogMaintenance(); 180c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} 181c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 182c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkovoid LogManager::OnRequestCompleted(const base::Time& timestamp, 183c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko const sockaddr* client_addr, 184c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko const std::string& method, 185c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko const std::string& url, 186c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko const std::string& version, 187c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko int status_code, 188830b1a87c3428b819eea1466557d3f058d5e2270Alex Vakulenko int64_t response_size) { 189c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko std::string ip_address = GetIPAddress(client_addr); 190c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko tm time_buf = {}; 191c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko char str_buf[32] = {}; 192c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Format the date/time as "25/Feb/2015:03:29:12 -0800". 193c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko time_t time = timestamp.ToTimeT(); 194c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko strftime(str_buf, sizeof(str_buf), "%d/%b/%Y:%H:%M:%S %z", 195c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko localtime_r(&time, &time_buf)); 196c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 197c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Log file entry for one HTTP request looking like this: 198c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // 127.0.0.1 - - [25/Feb/2015:03:29:12 -0800] "GET /test HTTP/1.1" 200 2326 199330a10fd406a37af8f9c530d9b51dc5e25fcdcebAlex Vakulenko std::string size_string{"-"}; 200330a10fd406a37af8f9c530d9b51dc5e25fcdcebAlex Vakulenko if (response_size >= 0) 201330a10fd406a37af8f9c530d9b51dc5e25fcdcebAlex Vakulenko size_string = std::to_string(response_size); 202c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko std::string log_entry = base::StringPrintf( 203330a10fd406a37af8f9c530d9b51dc5e25fcdcebAlex Vakulenko "%s - - [%s] \"%s %s %s\" %d %s\n", ip_address.c_str(), str_buf, 204330a10fd406a37af8f9c530d9b51dc5e25fcdcebAlex Vakulenko method.c_str(), url.c_str(), version.c_str(), status_code, 205330a10fd406a37af8f9c530d9b51dc5e25fcdcebAlex Vakulenko size_string.c_str()); 206c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko GetInstance()->logger_->Log(timestamp, log_entry); 207c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} 208c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 209c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkovoid LogManager::SetLogger(std::unique_ptr<LoggerInterface> logger) { 210c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko GetInstance()->logger_ = std::move(logger); 211c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} 212c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 213c16c6da6d632d6041997052edfbb97a674241517Alex VakulenkoLogManager* LogManager::GetInstance() { 214c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko return g_log_manager.Pointer(); 215c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} 216c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 217c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenkovoid LogManager::PerformLogMaintenance() { 218c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Get the list of all the log files in the log directory and put them into 219c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // a set which will sort the files by name (and effectively by the date since 220c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // we chose the file naming scheme deliberately to guarantee proper sorting 221c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // order). 222c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko std::set<base::FilePath> log_files; 223c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FileEnumerator enumerator{log_directory_, 224c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko false, 225c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FileEnumerator::FILES, 226c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko "*.log"}; 227c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko base::FilePath file = enumerator.Next(); 228c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko while (!file.empty()) { 229c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko log_files.insert(file); 230c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko file = enumerator.Next(); 231c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 232c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 233c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko // Now, if we have more files than we want to keep, purge the old files. 234c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko while (log_files.size() > kLogFilesToKeep) { 235c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko auto front_it = log_files.begin(); 236c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko PLOG_IF(WARNING, !base::DeleteFile(*front_it, false)) 237c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko << "Failed to delete an old log file: " << front_it->value(); 238c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko log_files.erase(front_it); 239c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko } 240c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} 241c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko 242c16c6da6d632d6041997052edfbb97a674241517Alex Vakulenko} // namespace webservd 243