| /** @file | |
| This contains the rotated log deletion mechanism. | |
| @section license License | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| #pragma once | |
| #include <cstdint> | |
| #include <deque> | |
| #include <memory> | |
| #include <string> | |
| #include <string_view> | |
| #include <time.h> | |
| #include <vector> | |
| #include "swoc/IntrusiveHashMap.h" | |
| /*------------------------------------------------------------------------- | |
| LogDeleteCandidate, LogDeletingInfo&Descriptor | |
| -------------------------------------------------------------------------*/ | |
| struct LogDeleteCandidate { | |
| /** The filename for this rolled log deletion candidate. | |
| * | |
| * For example: /var/log/my_log.log_a_host_name.20191122.20h18m35s-20191122.20h18m51s.old | |
| */ | |
| std::string rolled_log_path; | |
| int64_t size; | |
| time_t mtime; | |
| LogDeleteCandidate(std::string_view p_name, int64_t st_size, time_t st_time) | |
| : rolled_log_path(p_name), size(st_size), mtime(st_time) | |
| { | |
| } | |
| }; | |
| /** Configure rolled log deletion for a set of logs. | |
| * | |
| * This contains the configuration and set of log deletion candidates for a set | |
| * of log files associated with logname. There will be an instance of this for | |
| * diags.log and its associated rolled log files, one for traffic.out, etc. | |
| */ | |
| struct LogDeletingInfo { | |
| /** The unrolled log name (such as "diags.log"). */ | |
| const std::string logname; | |
| /** The minimum number of rolled log files to try to keep around. | |
| * | |
| * @note This is guaranteed to be a positive (non-zero) value. | |
| */ | |
| int min_count; | |
| std::vector<std::unique_ptr<LogDeleteCandidate>> candidates; | |
| LogDeletingInfo *_next{nullptr}; | |
| LogDeletingInfo *_prev{nullptr}; | |
| /** | |
| * @param[in] logname The unrolled log name. | |
| * | |
| * @param[in] min_count The minimum number of rolled files to try to keep | |
| * around when deleting rolled logs. A zero indicates a desire to keep all | |
| * rolled logs around. | |
| * | |
| * @note The min_count is used as a part of a calculation to determine which | |
| * set of deletion candidates should be used for selecting a rolled log file | |
| * to delete. If space is particularly constrained, even LogDeletingInfo | |
| * instances with a min_count of 0 may be selected for deletion. | |
| */ | |
| LogDeletingInfo(const char *logname, int min_count); | |
| LogDeletingInfo(std::string_view logname, int min_count); | |
| void | |
| clear() | |
| { | |
| candidates.clear(); | |
| } | |
| }; | |
| struct LogDeletingInfoDescriptor { | |
| using key_type = std::string_view; | |
| using value_type = LogDeletingInfo; | |
| static key_type | |
| key_of(value_type *value) | |
| { | |
| return value->logname; | |
| } | |
| static bool | |
| equal(key_type const &lhs, key_type const &rhs) | |
| { | |
| return lhs == rhs; | |
| } | |
| static value_type *& | |
| next_ptr(value_type *value) | |
| { | |
| return value->_next; | |
| } | |
| static value_type *& | |
| prev_ptr(value_type *value) | |
| { | |
| return value->_prev; | |
| } | |
| static constexpr std::hash<std::string_view> hasher{}; | |
| static auto | |
| hash_of(key_type s) -> decltype(hasher(s)) | |
| { | |
| return hasher(s); | |
| } | |
| }; | |
| /** | |
| * RolledLogDeleter is responsible for keeping track of rolled log candidates | |
| * and presenting them for deletion in a prioritized order based on size and | |
| * last modified time stamp. | |
| * | |
| * Terminology: | |
| * | |
| * log type: An unrolled log name that represents a category of rolled log | |
| * files that are candidates for deletion. This may be something like | |
| * diags.log, traffic.out, etc. | |
| * | |
| * candidate: A rolled log file which is a candidate for deletion at some | |
| * point. This may be something like: | |
| * squid.log_some.hostname.com.20191125.19h00m04s-20191125.19h15m04s.old. | |
| */ | |
| class RolledLogDeleter | |
| { | |
| public: | |
| /** Register a new log type for candidates for log deletion. | |
| * | |
| * @param[in] log_type The unrolled name for a set of rolled log files to | |
| * consider for deletion. This may be something like diags.log, for example. | |
| * | |
| * @param[in] rolling_min_count The minimum number of rolled log files to | |
| * keep around. | |
| */ | |
| void register_log_type_for_deletion(std::string_view log_type, int rolling_min_count); | |
| /** Evaluate a rolled log file to see whether it is a candidate for deletion. | |
| * | |
| * If the rolled log file is a valid candidate, it will be stored and considered | |
| * for deletion upon later calls to deleteALogFile. | |
| * | |
| * @param[in] log_path The rolled log file path. | |
| * | |
| * @param[in] file_size The size of the rolled log file. | |
| * | |
| * @param[in] modification_time The time the rolled log file was last modified. | |
| * candidate for deletion. | |
| * | |
| * @return True if the rolled log file is a deletion candidate, false otherwise. | |
| */ | |
| bool consider_for_candidacy(std::string_view log_path, int64_t file_size, time_t modification_time); | |
| /** Retrieve the next rolled log file to delete. | |
| * | |
| * This removes the returned rolled file from the candidates list. | |
| * | |
| * @return The next rolled log candidate to delete or nullptr if there is no | |
| * such candidate. | |
| */ | |
| std::unique_ptr<LogDeleteCandidate> take_next_candidate_to_delete(); | |
| /** Whether there are any candidates for possible deletion. | |
| * | |
| * @return True if there are candidates for deletion, false otherwise. | |
| */ | |
| bool has_candidates() const; | |
| /** Retrieve the number of rolled log deletion candidates. | |
| * | |
| * @return The number of rolled logs that are candidates for deletion. | |
| */ | |
| size_t get_candidate_count() const; | |
| /** Clear the internal candidates array. | |
| */ | |
| void clear_candidates(); | |
| private: | |
| /** Sort all the assembled candidates for each LogDeletingInfo. | |
| * | |
| * After any additions to the @a deleting_info, this should be called before | |
| * calling @a take_next_candidate_to_delete because the latter depends upon | |
| * the candidate entries being sorted. | |
| */ | |
| void sort_candidates(); | |
| private: | |
| /** The owning references to the set of LogDeletingInfo added to the below | |
| * hash map. */ | |
| std::deque<std::unique_ptr<LogDeletingInfo>> deletingInfoList; | |
| /** The set of candidates for deletion keyed by log_type. */ | |
| swoc::IntrusiveHashMap<LogDeletingInfoDescriptor> deleting_info; | |
| /** The number of tracked candidates. */ | |
| size_t num_candidates = 0; | |
| /** Whether the candidates require sorting due to an addition to the | |
| * deleting_info. */ | |
| bool candidates_require_sorting = true; | |
| }; |