1 /**
2  * @file src/megacmdlogger.cpp
3  * @brief MEGAcmd: Controls message logging
4  *
5  * (c) 2013 by Mega Limited, Auckland, New Zealand
6  *
7  * This file is part of the MEGAcmd.
8  *
9  * MEGAcmd is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * @copyright Simplified (2-clause) BSD License.
14  *
15  * You should have received a copy of the license along with this
16  * program.
17  */
18 
19 #include "megacmdlogger.h"
20 
21 #include <map>
22 
23 #include <sys/types.h>
24 
25 #ifdef _WIN32
26 #include <fcntl.h>
27 #include <io.h>
28 #include <stdio.h>
29 #ifndef _O_U16TEXT
30 #define _O_U16TEXT 0x00020000
31 #endif
32 #ifndef _O_U8TEXT
33 #define _O_U8TEXT 0x00040000
34 #endif
35 #endif
36 
37 using namespace mega;
38 
39 namespace megacmd {
40 // different outstreams for every thread. to gather all the output data
41 std::mutex threadLookups;
42 map<uint64_t, LoggedStream *> outstreams;
43 map<uint64_t, int> threadLogLevel;
44 map<uint64_t, int> threadoutCode;
45 map<uint64_t, CmdPetition *> threadpetition;
46 map<uint64_t, bool> threadIsCmdShell;
47 
48 LoggedStream LCOUT(&COUT);
49 
50 
getCurrentOut()51 LoggedStream &getCurrentOut()
52 {
53     std::lock_guard<std::mutex> g(threadLookups);
54     uint64_t currentThread = MegaThread::currentThreadId();
55     if (outstreams.find(currentThread) == outstreams.end())
56     {
57         return LCOUT;
58     }
59     else
60     {
61         return *outstreams[currentThread];
62     }
63 }
64 
interactiveThread()65 bool interactiveThread()
66 {
67     if (getCurrentThreadIsCmdShell())
68     {
69         return true;
70     }
71 
72     unsigned long long currentThread = MegaThread::currentThreadId();
73 
74     std::lock_guard<std::mutex> g(threadLookups);
75     if (outstreams.find(currentThread) == outstreams.end())
76     {
77         return true;
78     }
79     else
80     {
81         return false;
82     }
83 }
84 
getCurrentOutCode()85 int getCurrentOutCode()
86 {
87     unsigned long long currentThread = MegaThread::currentThreadId();
88 
89     std::lock_guard<std::mutex> g(threadLookups);
90     if (threadoutCode.find(currentThread) == threadoutCode.end())
91     {
92         return 0; //default OK
93     }
94     else
95     {
96         return threadoutCode[currentThread];
97     }
98 }
99 
100 
getCurrentPetition()101 CmdPetition * getCurrentPetition()
102 {
103     unsigned long long currentThread = MegaThread::currentThreadId();
104 
105     std::lock_guard<std::mutex> g(threadLookups);
106     if (threadpetition.find(currentThread) == threadpetition.end())
107     {
108         return NULL;
109     }
110     else
111     {
112         return threadpetition[currentThread];
113     }
114 }
115 
getCurrentThreadLogLevel()116 int getCurrentThreadLogLevel()
117 {
118     unsigned long long currentThread = MegaThread::currentThreadId();
119 
120     std::lock_guard<std::mutex> g(threadLookups);
121     if (threadLogLevel.find(currentThread) == threadLogLevel.end())
122     {
123         return -1;
124     }
125     else
126     {
127         return threadLogLevel[currentThread];
128     }
129 }
130 
getCurrentThreadIsCmdShell()131 bool getCurrentThreadIsCmdShell()
132 {
133     unsigned long long currentThread = MegaThread::currentThreadId();
134 
135     std::lock_guard<std::mutex> g(threadLookups);
136     if (threadIsCmdShell.find(currentThread) == threadIsCmdShell.end())
137     {
138         return false; //default not
139     }
140     else
141     {
142         return threadIsCmdShell[currentThread];
143     }
144 }
145 
146 
setCurrentThreadLogLevel(int level)147 void setCurrentThreadLogLevel(int level)
148 {
149     std::lock_guard<std::mutex> g(threadLookups);
150     threadLogLevel[MegaThread::currentThreadId()] = level;
151 }
152 
setCurrentThreadOutStream(LoggedStream * s)153 void setCurrentThreadOutStream(LoggedStream *s)
154 {
155     std::lock_guard<std::mutex> g(threadLookups);
156     outstreams[MegaThread::currentThreadId()] = s;
157 }
158 
setCurrentThreadIsCmdShell(bool isit)159 void setCurrentThreadIsCmdShell(bool isit)
160 {
161     std::lock_guard<std::mutex> g(threadLookups);
162     threadIsCmdShell[MegaThread::currentThreadId()] = isit;
163 }
164 
setCurrentOutCode(int outCode)165 void setCurrentOutCode(int outCode)
166 {
167     std::lock_guard<std::mutex> g(threadLookups);
168     threadoutCode[MegaThread::currentThreadId()] = outCode;
169 }
170 
setCurrentPetition(CmdPetition * petition)171 void setCurrentPetition(CmdPetition *petition)
172 {
173     std::lock_guard<std::mutex> g(threadLookups);
174     threadpetition[MegaThread::currentThreadId()] = petition;
175 }
176 
177 
MegaCMDLogger()178 MegaCMDLogger::MegaCMDLogger()
179 {
180     this->output = &LCOUT;
181     this->apiLoggerLevel = MegaApi::LOG_LEVEL_ERROR;
182     this->outputmutex = new std::mutex();
183 }
184 
~MegaCMDLogger()185 MegaCMDLogger::~MegaCMDLogger()
186 {
187     delete this->outputmutex;
188 }
189 
log(const char * time,int loglevel,const char * source,const char * message)190 void MegaCMDLogger::log(const char *time, int loglevel, const char *source, const char *message)
191 {
192     if ( (string(source).find("src/megacmd") != string::npos)
193          || (string(source).find("src\\megacmd") != string::npos)
194          || (string(source).find("listeners.cpp") != string::npos)
195          || (string(source).find("configurationmanager.cpp") != string::npos)
196          || (string(source).find("comunicationsmanager") != string::npos)
197          )
198     {
199         if (loglevel <= cmdLoggerLevel)
200         {
201 #ifdef _WIN32
202             std::lock_guard<std::mutex> g(*outputmutex);
203             int oldmode;
204             oldmode = _setmode(_fileno(stdout), _O_U8TEXT);
205             *output << "[" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
206             _setmode(_fileno(stdout), oldmode);
207 #else
208             *output << "[" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
209 #endif
210 
211         }
212 
213         int currentThreadLogLevel = getCurrentThreadLogLevel();
214         if (currentThreadLogLevel < 0)
215         {
216             currentThreadLogLevel = cmdLoggerLevel;
217         }
218         if (( loglevel <= currentThreadLogLevel ) && ( &OUTSTREAM != output ))
219         {
220             OUTSTREAM << "[" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
221         }
222     }
223     else
224     {
225         if (loglevel <= apiLoggerLevel)
226         {
227             if (( apiLoggerLevel <= MegaApi::LOG_LEVEL_DEBUG ) && !strcmp(message, "Request (RETRY_PENDING_CONNECTIONS) starting"))
228             {
229                 return;
230             }
231             if (( apiLoggerLevel <= MegaApi::LOG_LEVEL_DEBUG ) && !strcmp(message, "Request (RETRY_PENDING_CONNECTIONS) finished"))
232             {
233                 return;
234             }
235 #ifdef _WIN32
236             std::lock_guard<std::mutex> g(*outputmutex);
237             int oldmode;
238             oldmode = _setmode(_fileno(stdout), _O_U8TEXT);
239             *output << "[API:" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
240             _setmode(_fileno(stdout), oldmode);
241 #else
242             *output << "[API:" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
243 #endif
244         }
245 
246         int currentThreadLogLevel = getCurrentThreadLogLevel();
247 
248         if (currentThreadLogLevel < 0)
249         {
250             currentThreadLogLevel = apiLoggerLevel;
251         }
252         if (( loglevel <= currentThreadLogLevel ) && ( &OUTSTREAM != output )) //since it happens in the sdk thread, this shall be false
253         {
254             OUTSTREAM << "[API:" << SimpleLogger::toStr(LogLevel(loglevel)) << ": " << time << "] " << message << endl;
255         }
256     }
257 }
258 
getMaxLogLevel()259 int MegaCMDLogger::getMaxLogLevel()
260 {
261     return max(max(getCurrentThreadLogLevel(), cmdLoggerLevel), apiLoggerLevel);
262 }
263 
264 }//end namespace
265