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 | |