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
24using namespace Aws::Utils;
25using namespace Aws::Utils::Logging;
26
27static const char* AllocationTag = "DefaultLogSystem";
28static const int BUFFERED_MSG_COUNT = 100;
29
30static 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
36static 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
80DefaultLogSystem::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
88DefaultLogSystem::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
96DefaultLogSystem::~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
108void 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
123void DefaultLogSystem::Flush()
124{
125 m_syncData.m_queueSignal.notify_one();
126}
127
128