1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18 #ifndef itkLoggerThreadWrapper_hxx
19 #define itkLoggerThreadWrapper_hxx
20
21 #include <iostream>
22 #include "itkLoggerThreadWrapper.h"
23 #include "itksys/SystemTools.hxx"
24
25 namespace itk
26 {
27 /** Set the priority level for the current logger. Only messages that have
28 * priorities equal or greater than the one set here will be posted to the
29 * current outputs */
30 template< typename SimpleLoggerType >
SetPriorityLevel(PriorityLevelType level)31 void LoggerThreadWrapper< SimpleLoggerType >::SetPriorityLevel(PriorityLevelType level)
32 {
33 this->m_Mutex.lock();
34 this->m_OperationQ.push(SET_PRIORITY_LEVEL);
35 this->m_LevelQ.push(level);
36 this->m_Mutex.unlock();
37 }
38
39 /** Get the priority level for the current logger. Only messages that have
40 * priorities equal or greater than the one set here will be posted to the
41 * current outputs */
42 template< typename SimpleLoggerType >
GetPriorityLevel() const43 typename SimpleLoggerType::PriorityLevelType LoggerThreadWrapper< SimpleLoggerType >::GetPriorityLevel() const
44 {
45 this->m_Mutex.lock();
46 PriorityLevelType level = this->m_PriorityLevel;
47 this->m_Mutex.unlock();
48 return level;
49 }
50
51 template< typename SimpleLoggerType >
SetLevelForFlushing(PriorityLevelType level)52 void LoggerThreadWrapper< SimpleLoggerType >::SetLevelForFlushing(PriorityLevelType level)
53 {
54 this->m_Mutex.lock();
55 this->m_LevelForFlushing = level;
56 this->m_OperationQ.push(SET_LEVEL_FOR_FLUSHING);
57 this->m_LevelQ.push(level);
58 this->m_Mutex.unlock();
59 }
60
61 template< typename SimpleLoggerType >
GetLevelForFlushing() const62 typename SimpleLoggerType::PriorityLevelType LoggerThreadWrapper< SimpleLoggerType >::GetLevelForFlushing() const
63 {
64 this->m_Mutex.lock();
65 PriorityLevelType level = this->m_LevelForFlushing;
66 this->m_Mutex.unlock();
67 return level;
68 }
69
70 template< typename SimpleLoggerType >
SetDelay(DelayType delay)71 void LoggerThreadWrapper< SimpleLoggerType >::SetDelay(DelayType delay)
72 {
73 this->m_Mutex.lock();
74 this->m_Delay = delay;
75 this->m_Mutex.unlock();
76 }
77
78 template< typename SimpleLoggerType >
GetDelay() const79 typename LoggerThreadWrapper< SimpleLoggerType >::DelayType LoggerThreadWrapper< SimpleLoggerType >::GetDelay() const
80 {
81 this->m_Mutex.lock();
82 DelayType delay = this->m_Delay;
83 this->m_Mutex.unlock();
84 return delay;
85 }
86
87 /** Adds an output stream to the MultipleLogOutput for writing. */
88 template< typename SimpleLoggerType >
AddLogOutput(OutputType * output)89 void LoggerThreadWrapper< SimpleLoggerType >::AddLogOutput(OutputType *output)
90 {
91 this->m_Mutex.lock();
92 this->m_OperationQ.push(ADD_LOG_OUTPUT);
93 this->m_OutputQ.push(output);
94 this->m_Mutex.unlock();
95 }
96
97 template< typename SimpleLoggerType >
Write(PriorityLevelType level,std::string const & content)98 void LoggerThreadWrapper< SimpleLoggerType >::Write(PriorityLevelType level, std::string const & content)
99 {
100 this->m_Mutex.lock();
101 if ( this->m_PriorityLevel >= level )
102 {
103 this->m_OperationQ.push(WRITE);
104 this->m_MessageQ.push(content);
105 this->m_LevelQ.push(level);
106 }
107 this->m_Mutex.unlock();
108 if ( this->m_LevelForFlushing >= level )
109 {
110 this->Flush();
111 }
112 }
113
114 template< typename SimpleLoggerType >
Flush()115 void LoggerThreadWrapper< SimpleLoggerType >::Flush()
116 {
117 this->m_Mutex.lock();
118
119 while ( !this->m_OperationQ.empty() )
120 {
121 switch ( this->m_OperationQ.front() )
122 {
123 case Self::SET_PRIORITY_LEVEL:
124 this->m_PriorityLevel = this->m_LevelQ.front();
125 this->m_LevelQ.pop();
126 break;
127 case Self::SET_LEVEL_FOR_FLUSHING:
128 this->m_LevelForFlushing = this->m_LevelQ.front();
129 this->m_LevelQ.pop();
130 break;
131
132 case Self::ADD_LOG_OUTPUT:
133 this->m_Output->AddLogOutput( this->m_OutputQ.front() );
134 this->m_OutputQ.pop();
135 break;
136
137 case Self::WRITE:
138 this->SimpleLoggerType::Write( this->m_LevelQ.front(), this->m_MessageQ.front() );
139 this->m_LevelQ.pop();
140 this->m_MessageQ.pop();
141 break;
142 }
143 this->m_OperationQ.pop();
144 }
145 this->SimpleLoggerType::Flush();
146 this->m_Output->Flush();
147 this->m_Mutex.unlock();
148 }
149
150 /** Constructor */
151 template< typename SimpleLoggerType >
LoggerThreadWrapper()152 LoggerThreadWrapper< SimpleLoggerType >::LoggerThreadWrapper()
153 {
154 m_Delay = 300; // ms
155 m_TerminationRequested = false;
156 m_Thread = std::thread(&Self::ThreadFunction, this);
157 }
158
159 /** Destructor */
160 template< typename SimpleLoggerType >
~LoggerThreadWrapper()161 LoggerThreadWrapper< SimpleLoggerType >::~LoggerThreadWrapper()
162 {
163 this->Flush();
164 if( m_Thread.joinable() )
165 {
166 m_TerminationRequested = true;
167 m_Thread.join(); //waits for it to finish if necessary
168 }
169 }
170
171 template< typename SimpleLoggerType >
172 void
173 LoggerThreadWrapper< SimpleLoggerType >
ThreadFunction()174 ::ThreadFunction()
175 {
176 while ( !m_TerminationRequested )
177 {
178 m_Mutex.lock();
179 while ( !m_OperationQ.empty() )
180 {
181 switch ( m_OperationQ.front() )
182 {
183 case Self::SET_PRIORITY_LEVEL:
184 this->m_PriorityLevel = m_LevelQ.front();
185 m_LevelQ.pop();
186 break;
187
188 case Self::SET_LEVEL_FOR_FLUSHING:
189 this->m_LevelForFlushing = m_LevelQ.front();
190 m_LevelQ.pop();
191 break;
192
193 case Self::ADD_LOG_OUTPUT:
194 this->m_Output->AddLogOutput( m_OutputQ.front() );
195 m_OutputQ.pop();
196 break;
197
198 case Self::WRITE:
199 SimpleLoggerType::Write( m_LevelQ.front(), m_MessageQ.front() );
200 m_LevelQ.pop();
201 m_MessageQ.pop();
202 break;
203 }
204 m_OperationQ.pop();
205 }
206 m_Mutex.unlock();
207 SimpleLoggerType::Flush();
208 itksys::SystemTools::Delay(this->GetDelay());
209 }
210 }
211
212 /** Print contents of a LoggerThreadWrapper */
213 template< typename SimpleLoggerType >
PrintSelf(std::ostream & os,Indent indent) const214 void LoggerThreadWrapper< SimpleLoggerType >::PrintSelf(std::ostream & os, Indent indent) const
215 {
216 Superclass::PrintSelf(os, indent);
217
218 os << indent << "Thread ID: " << this->m_Thread.get_id() << std::endl;
219 os << indent << "Low-priority Message Delay: " << this->m_Delay << std::endl;
220 os << indent << "Operation Queue Size: " << this->m_OperationQ.size() << std::endl;
221 os << indent << "Message Queue Size: " << this->m_MessageQ.size() << std::endl;
222 os << indent << "Level Queue Size: " << this->m_LevelQ.size() << std::endl;
223 os << indent << "Output Queue Size: " << this->m_OutputQ.size() << std::endl;
224 }
225 } // namespace itk
226
227 #endif // itkLoggerThreadWrapper_hxx
228