| 1 | /* |
| 2 | * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
| 5 | * You may not use this file except in compliance with the License. |
| 6 | * A copy of the License is located at |
| 7 | * |
| 8 | * http://aws.amazon.com/apache2.0 |
| 9 | * |
| 10 | * or in the "license" file accompanying this file. This file is distributed |
| 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| 12 | * express or implied. See the License for the specific language governing |
| 13 | * permissions and limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | |
| 17 | #include <aws/core/utils/logging/DefaultLogSystem.h> |
| 18 | |
| 19 | #include <aws/core/utils/DateTime.h> |
| 20 | #include <aws/core/utils/memory/stl/AWSVector.h> |
| 21 | |
| 22 | #include <fstream> |
| 23 | |
| 24 | using namespace Aws::Utils; |
| 25 | using namespace Aws::Utils::Logging; |
| 26 | |
| 27 | static const char* AllocationTag = "DefaultLogSystem" ; |
| 28 | static const int BUFFERED_MSG_COUNT = 100; |
| 29 | |
| 30 | static std::shared_ptr<Aws::OFStream> MakeDefaultLogFile(const Aws::String& filenamePrefix) |
| 31 | { |
| 32 | Aws::String newFileName = filenamePrefix + DateTime::CalculateGmtTimestampAsString("%Y-%m-%d-%H" ) + ".log" ; |
| 33 | return Aws::MakeShared<Aws::OFStream>(AllocationTag, newFileName.c_str(), Aws::OFStream::out | Aws::OFStream::app); |
| 34 | } |
| 35 | |
| 36 | static void LogThread(DefaultLogSystem::LogSynchronizationData* syncData, const std::shared_ptr<Aws::OStream>& logFile, const Aws::String& filenamePrefix, bool rollLog) |
| 37 | { |
| 38 | // localtime requires access to env. variables to get Timezone, which is not thread-safe |
| 39 | int32_t lastRolledHour = DateTime::Now().GetHour(false /*localtime*/); |
| 40 | std::shared_ptr<Aws::OStream> log = logFile; |
| 41 | |
| 42 | for(;;) |
| 43 | { |
| 44 | std::unique_lock<std::mutex> locker(syncData->m_logQueueMutex); |
| 45 | syncData->m_queueSignal.wait(locker, [&](){ return syncData->m_stopLogging == true || syncData->m_queuedLogMessages.size() > 0; } ); |
| 46 | |
| 47 | if (syncData->m_stopLogging && syncData->m_queuedLogMessages.size() == 0) |
| 48 | { |
| 49 | break; |
| 50 | } |
| 51 | |
| 52 | Aws::Vector<Aws::String> messages(std::move(syncData->m_queuedLogMessages)); |
| 53 | syncData->m_queuedLogMessages.reserve(BUFFERED_MSG_COUNT); |
| 54 | |
| 55 | locker.unlock(); |
| 56 | |
| 57 | if (messages.size() > 0) |
| 58 | { |
| 59 | if (rollLog) |
| 60 | { |
| 61 | // localtime requires access to env. variables to get Timezone, which is not thread-safe |
| 62 | int32_t currentHour = DateTime::Now().GetHour(false /*localtime*/); |
| 63 | if (currentHour != lastRolledHour) |
| 64 | { |
| 65 | log = MakeDefaultLogFile(filenamePrefix); |
| 66 | lastRolledHour = currentHour; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | for (const auto& msg : messages) |
| 71 | { |
| 72 | (*log) << msg; |
| 73 | } |
| 74 | |
| 75 | log->flush(); |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | DefaultLogSystem::DefaultLogSystem(LogLevel logLevel, const std::shared_ptr<Aws::OStream>& logFile) : |
| 81 | Base(logLevel), |
| 82 | m_syncData(), |
| 83 | m_loggingThread() |
| 84 | { |
| 85 | m_loggingThread = std::thread(LogThread, &m_syncData, logFile, "" , false); |
| 86 | } |
| 87 | |
| 88 | DefaultLogSystem::DefaultLogSystem(LogLevel logLevel, const Aws::String& filenamePrefix) : |
| 89 | Base(logLevel), |
| 90 | m_syncData(), |
| 91 | m_loggingThread() |
| 92 | { |
| 93 | m_loggingThread = std::thread(LogThread, &m_syncData, MakeDefaultLogFile(filenamePrefix), filenamePrefix, true); |
| 94 | } |
| 95 | |
| 96 | DefaultLogSystem::~DefaultLogSystem() |
| 97 | { |
| 98 | { |
| 99 | std::lock_guard<std::mutex> locker(m_syncData.m_logQueueMutex); |
| 100 | m_syncData.m_stopLogging = true; |
| 101 | } |
| 102 | |
| 103 | m_syncData.m_queueSignal.notify_one(); |
| 104 | |
| 105 | m_loggingThread.join(); |
| 106 | } |
| 107 | |
| 108 | void DefaultLogSystem::ProcessFormattedStatement(Aws::String&& statement) |
| 109 | { |
| 110 | std::unique_lock<std::mutex> locker(m_syncData.m_logQueueMutex); |
| 111 | m_syncData.m_queuedLogMessages.emplace_back(std::move(statement)); |
| 112 | if(m_syncData.m_queuedLogMessages.size() >= BUFFERED_MSG_COUNT) |
| 113 | { |
| 114 | locker.unlock(); |
| 115 | m_syncData.m_queueSignal.notify_one(); |
| 116 | } |
| 117 | else |
| 118 | { |
| 119 | locker.unlock(); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | void DefaultLogSystem::Flush() |
| 124 | { |
| 125 | m_syncData.m_queueSignal.notify_one(); |
| 126 | } |
| 127 | |
| 128 | |