Salome HOME
PR: bug 7769 loader aborts when logger not found in naming service,
[modules/kernel.git] / src / SALOMETraceCollector / SALOMETraceCollector.cxx
1 //  Copyright (C) 2004  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
3 // 
4 //  This library is free software; you can redistribute it and/or 
5 //  modify it under the terms of the GNU Lesser General Public 
6 //  License as published by the Free Software Foundation; either 
7 //  version 2.1 of the License. 
8 // 
9 //  This library 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.  See the GNU 
12 //  Lesser General Public License for more details. 
13 // 
14 //  You should have received a copy of the GNU Lesser General Public 
15 //  License along with this library; if not, write to the Free Software 
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
17 // 
18 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
19 //
20 //
21 //
22 //  File   : LocalTraceCollector.cxx
23 //  Author : Paul RASCLE (EDF)
24 //  Module : KERNEL
25 //  $Header$
26
27 #include <iostream>
28 #include <sstream>
29 #include <fstream>
30 #include <cstdlib>
31 #include <CORBA.h>
32
33 using namespace std;
34
35 #include "SALOMETraceCollector.hxx"
36 #include "TraceCollector_WaitForServerReadiness.hxx"
37 //#include "SALOME_Log.hxx"
38 #include <SALOMEconfig.h>
39 #include CORBA_CLIENT_HEADER(Logger)
40
41 // Class attributes initialisation, for class method SALOMETraceCollector::run
42
43 SALOMETraceCollector* SALOMETraceCollector::_singleton = 0;
44 pthread_mutex_t SALOMETraceCollector::_singletonMutex;
45 int SALOMETraceCollector::_threadToClose = 0;
46 pthread_t SALOMETraceCollector::_threadId = 0; // used to control single run
47 int SALOMETraceCollector::_toFile = 0;
48 std::string SALOMETraceCollector::_fileName = "";
49 CORBA::ORB_ptr SALOMETraceCollector::_orb = 0;
50
51 // ============================================================================
52 /*!
53  *  This class replaces LocalTraceCollector, which is to use outside SALOME,
54  *  without CORBA.
55  *
56  *  guarantees a unique object instance of the class (singleton thread safe)
57  *  a separate thread for loop to print traces is launched.
58  *  \param typeTrace 0=standard out, 1=file(/tmp/tracetest.log), 2=CORBA log
59  *  If typeTrace=0, checks environment for "SALOME_trace". Test values in
60  *  the following order:
61  *  - "local"  standard out
62  *  - "with_logger" CORBA log
63  *  - anything else is kept as a file name
64  */
65 // ============================================================================
66
67 SALOMETraceCollector* SALOMETraceCollector::instance(CORBA::ORB_ptr theOrb,
68                                                    int typeTrace)
69 {
70   if (_singleton == 0) // no need of lock when singleton already exists
71     {
72       int ret;
73       ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
74       if (_singleton == 0)                     // another thread may have got
75         {                                      // the lock after the first test
76           _singleton = new SALOMETraceCollector();
77
78           _fileName = "/tmp/tracetest.log";
79           _toFile=0;
80           _orb = theOrb;
81           if (typeTrace)       // caller sets a value different from default=0
82             _toFile = typeTrace; 
83           else                 // check environment
84             {
85               char* traceKind = getenv("SALOME_trace");
86               //cout<<"SALOME_trace="<<traceKind<<endl;
87               if (traceKind)
88                 {
89                   if (strcmp(traceKind,"local")==0) _toFile=0;
90                   else if (strcmp(traceKind,"with_logger")==0) _toFile=2;
91                   else
92                     {
93                       _toFile=1;
94                       _fileName = traceKind;
95                     }       
96                 }
97             }
98           //cout <<"_toFile: "<<_toFile<<" _fileName: "<<_fileName<<endl;
99
100           pthread_t traceThread;
101           int bid;
102           int re2 = pthread_create(&traceThread, NULL,
103                                    SALOMETraceCollector::run, (void *)bid);
104         }
105       ret = pthread_mutex_unlock(&_singletonMutex); // release lock
106     }
107   return _singleton;
108 }
109
110 // ============================================================================
111 /*!
112  *  In a separate thread, loop to print traces.
113  *  Mutex garantees intialisation on instance method is done and only one run
114  *  allowed (double check ...)
115  *  Loop until there is no more buffer to print,
116  *  and no ask for end from destructor.
117  *  Get a buffer. If type = ABORT then exit application with message.
118  */
119 // ============================================================================
120
121 void* SALOMETraceCollector::run(void *bid)
122 {
123   int isOKtoRun = 0;
124   int ret = pthread_mutex_lock(&_singletonMutex); // acquire lock to be alone
125   if (! _threadId)  // only one run
126     {
127       isOKtoRun = 1;
128       _threadId = pthread_self();
129     }
130   else cout << "----- Comment est-ce possible de passer la ? -------" <<endl;
131   ret = pthread_mutex_unlock(&_singletonMutex); // release lock
132
133   if (isOKtoRun)
134     { 
135       _threadId = pthread_self();
136       LocalTraceBufferPool* myTraceBuffer = LocalTraceBufferPool::instance();
137       LocalTrace_TraceInfo myTrace;
138
139       // if trace in file requested, opens a file with append mode
140       // so, several processes can share the same file
141       // if CORBA collection requested, wait for Logger server readiness
142
143       ofstream traceFile;
144       SALOME_Logger::Logger_var m_pInterfaceLogger;
145       CORBA::Object_var obj;
146
147       switch (_toFile)
148         {
149         case 1 :  // --- trace to file
150           {
151             const char *fileName = _fileName.c_str();
152             traceFile.open(fileName, ios::out | ios::app);
153             if (!traceFile)
154               {
155                 cerr << "impossible to open trace file "<< fileName << endl;
156                 exit (1);
157               }
158           }
159           break;
160         case 2 :  // --- trace collection via CORBA
161           obj = TraceCollector_WaitForServerReadiness(_orb,"Logger");
162           if (!CORBA::is_nil(obj))
163             m_pInterfaceLogger = SALOME_Logger::Logger::_narrow(obj);
164           if (CORBA::is_nil(m_pInterfaceLogger))
165             {
166               cerr << "Logger server not found ! Abort" << endl;
167               cerr << flush ; 
168               exit(1);
169             } 
170           else
171             {
172               CORBA::String_var LogMsg =
173                 CORBA::string_dup("\n---Init logger trace---\n");
174               m_pInterfaceLogger->putMessage(LogMsg);
175               //cout << " Logger server found" << endl;
176             }
177           break;
178         case 0 : ; // --- trace to standard output
179         default :  // --- on standard output, too
180           break;
181         }
182
183       // Loop until there is no more buffer to print,
184       // and no ask for end from destructor.
185
186       while ((!_threadToClose) || myTraceBuffer->toCollect() )
187         {
188           int fullBuf = myTraceBuffer->retrieve(myTrace);
189           if (myTrace.traceType == ABORT_MESS)
190             {
191               switch (_toFile)
192                 {
193                 case 2 :  // --- trace collection via CORBA
194                   {
195                     stringstream abortMessage("");
196                     abortMessage << "INTERRUPTION from thread "
197                                  << myTrace.threadId << " : " << myTrace.trace;
198                     CORBA::String_var LogMsg =
199                       CORBA::string_dup(abortMessage.str().c_str());
200                     m_pInterfaceLogger->putMessage(LogMsg);
201                     exit(1);
202                   }
203                   break;
204                 case 1 :  // --- trace to file
205                   traceFile << "INTERRUPTION from thread " << myTrace.threadId
206                             << " : " <<  myTrace.trace;
207                   traceFile.close();
208                   // no break here !
209                 case 0 :  // --- trace to standard output
210                 default : // --- on standard output, too
211                   cout << flush ;
212                   cerr << "INTERRUPTION from thread " << myTrace.threadId
213                        << " : " <<  myTrace.trace;
214                   cerr << flush ; 
215                   exit(1);     
216                   break;
217                 }
218             }
219           else
220             {
221               switch (_toFile)
222                 {
223                 case 2 :  // --- trace collection via CORBA
224                   {
225                     stringstream aMessage("");
226                     aMessage << "th. " << myTrace.threadId
227                              << " " << myTrace.trace;
228                     CORBA::String_var LogMsg =
229                       CORBA::string_dup(aMessage.str().c_str());
230                     m_pInterfaceLogger->putMessage(LogMsg);
231                   }
232                   break;
233                 case 1 :  // --- trace to file
234                   traceFile << "th. " << myTrace.threadId
235                             << " " << myTrace.trace;
236                   break;
237                 case 0 :  // --- trace to standard output
238                 default : // --- on standard output, too
239                   cout << "th. " << myTrace.threadId << " " << myTrace.trace;
240                   break;
241                 }
242             }
243         }
244
245       if (_toFile==1) traceFile.close();
246     }
247   pthread_exit(NULL);
248 }
249
250 // ============================================================================
251 /*!
252  *  Destructor: wait until printing thread ends (SALOMETraceCollector::run)
253  */
254 // ============================================================================
255
256 SALOMETraceCollector:: ~SALOMETraceCollector()
257 {
258   LocalTraceBufferPool* myTraceBuffer = LocalTraceBufferPool::instance();
259   _threadToClose = 1;
260   myTraceBuffer->insert(NORMAL_MESS,"end of trace "); //needed to wake up thread
261   if (_threadId)
262     {
263       int ret = pthread_join(_threadId, NULL);
264       if (ret) cout << "error close SALOMETraceCollector : "<< ret << endl;
265       else cout << "SALOMETraceCollector destruction OK" << endl;
266     }
267   delete myTraceBuffer;
268 }
269
270 // ============================================================================
271 /*!
272  * Constructor: no need of LocalTraceBufferPool object initialization here,
273  * thread safe singleton used in LocalTraceBufferPool::instance()
274  */
275 // ============================================================================
276
277 SALOMETraceCollector::SALOMETraceCollector()
278 {
279   _threadId=0;
280 }
281
282