Salome HOME
54a8b90d56a3d9c2e21b820bccb9a804c534f31b
[modules/kernel.git] / src / Launcher / SALOME_LogManager.cxx
1 // Copyright (C) 2024  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SALOME_LogManager.hxx"
21 #include "SALOME_Fake_NamingService.hxx"
22 #include "SALOME_ContainerManager.hxx"
23
24 #ifndef WIN32
25 #include <unistd.h>
26 #else
27 #include <windows.h>
28 #include <Basics_Utils.hxx>
29 #endif
30
31 #include <sstream>
32 #include <fstream>
33 #include <algorithm>
34 #include <memory>
35 #include <functional>
36
37 const char SALOME_LogManager::NAME_IN_NS[]="/LogManager";
38
39 static std::vector<char> FromPyToCpp(PyObject *obj)
40 {
41   std::vector<char> ret;
42   char *buffer = nullptr;
43   Py_ssize_t length = 0;
44   PyBytes_AsStringAndSize(obj,&buffer,&length);
45   ret.resize(length);
46   for(auto i = 0 ; i < length ; ++i)
47     ret[i] = buffer[i];
48   return ret;
49 }
50
51 static SALOME::vectorOfByte *FromVectCharToCorba(const std::vector<char>& data)
52 {
53   SALOME::vectorOfByte_var ret = new SALOME::vectorOfByte;
54   auto length = data.size();
55   ret->length(length);
56   for(auto i = 0 ; i < length ; ++i)
57     ret[i] = data[i];
58   return ret._retn();
59 }
60
61 PortableServer::POA_var SALOME_ContainerScriptExecPerfLog::getPOA()
62 {
63   return father()->getPOA();
64 }
65
66 void SALOME_ContainerScriptExecPerfLog::assign(const SALOME::vectorOfByte& value)
67 {
68   auto sz = value.length();
69   _data.resize( sz );
70   for(auto i = 0 ; i < sz ; ++i)
71     _data[i] = value[i];
72   //
73   AutoPyRef s( this->end( ) );
74   //
75   _data = FromPyToCpp(s);
76 }
77
78 SALOME::vectorOfByte *SALOME_ContainerScriptExecPerfLog::getObj()
79 {
80   return FromVectCharToCorba(this->_data);
81 }
82
83 void SALOME_ContainerScriptExecPerfLog::accept(SALOME_VisitorContainerLog &visitor)
84 {
85   visitor.visitContainerScriptExecPerfLog( *this );
86 }
87
88 void SALOME_ContainerScriptExecPerfLog::start()
89 {
90   AutoGIL gstate;
91   AutoPyRef result = PyObject_CallMethod(pyObj(),(char*)"start","",nullptr);
92   if (PyErr_Occurred())
93   {
94     std::string error("can not start");
95     PyErr_Print();
96     THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
97   }
98 }
99
100 AutoPyRef SALOME_ContainerScriptExecPerfLog::end()
101 {
102   AutoGIL gstate;
103   //https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue
104   AutoPyRef dataPy(PyBytes_FromStringAndSize(_data.data(),_data.size()));
105   AutoPyRef result(PyObject_CallMethod(pyObj(),(char*)"end","O",dataPy.get(),nullptr) ) ;
106   if (PyErr_Occurred())
107   {
108     std::string error("can not end");
109     PyErr_Print();
110     THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
111   }
112   return result;
113 }
114
115 /////
116
117 PortableServer::POA_var SALOME_ContainerScriptPerfLog::getPOA()
118 {
119   return father()->getPOA();
120 }
121
122 char *SALOME_ContainerScriptPerfLog::getCode()
123 {
124   return CORBA::string_dup( _code.c_str() );
125 }
126
127 char *SALOME_ContainerScriptPerfLog::getName()
128 {
129   return CORBA::string_dup( _name.c_str() );
130 }
131
132 void SALOME_ContainerScriptPerfLog::accept(SALOME_VisitorContainerLog &visitor)
133 {
134   visitor.enterContainerScriptPerfLog( *this );
135   for(auto session : _sessions)
136   {
137     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( session );
138     serv->_remove_ref();
139     SALOME_ContainerScriptExecPerfLog *servC = dynamic_cast<SALOME_ContainerScriptExecPerfLog *>(serv);
140     visitor.visitContainerScriptExecPerfLog( *servC );
141   }
142   visitor.leaveContainerScriptPerfLog( *this );
143 }
144
145 Engines::ContainerScriptExecPerfLog_ptr SALOME_ContainerScriptPerfLog::addExecutionSession()
146 {
147   SALOME_ContainerScriptExecPerfLog *execution = new SALOME_ContainerScriptExecPerfLog(this);
148   PortableServer::ObjectId_var id(getPOA()->activate_object(execution));
149   execution->_remove_ref();
150   CORBA::Object_var executionPtr(getPOA()->id_to_reference(id));
151   Engines::ContainerScriptExecPerfLog_var executionPtr2 = Engines::ContainerScriptExecPerfLog::_narrow(executionPtr);
152   _sessions.push_back( executionPtr2 );
153   {
154     AutoGIL gstate;
155     AutoPyRef result = PyObject_CallMethod(pyObj(),(char*)"addExecution","",nullptr);
156     if (PyErr_Occurred())
157     {
158       std::string error("can not addExecution");
159       PyErr_Print();
160       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
161     }
162     execution->setPyObj( result.retn() );//ownership of result is transfered to execution
163   }
164   execution->start();
165   return executionPtr2._retn();
166 }
167
168 Engines::ListOfContainerScriptExecPerfLog *SALOME_ContainerScriptPerfLog::listOfExecs()
169 {
170   Engines::ListOfContainerScriptExecPerfLog_var ret = new Engines::ListOfContainerScriptExecPerfLog;
171   auto sz = this->_sessions.size();
172   ret->length(sz);
173   for(auto i = 0 ; i < sz ; ++i)
174     ret[i] = this->_sessions[i];
175   return ret._retn();
176 }
177
178 /////
179
180 PortableServer::POA_var SALOME_ContainerPerfLog::getPOA()
181 {
182   return father()->getPOA();
183   }
184
185 Engines::ContainerScriptPerfLog_ptr SALOME_ContainerPerfLog::addScript(const char *name, const char *code)
186 {
187   SALOME_ContainerScriptPerfLog *script = new SALOME_ContainerScriptPerfLog(this,name,code);
188   PortableServer::ObjectId_var id(getPOA()->activate_object(script));
189   script->_remove_ref();
190   CORBA::Object_var scriptPtr(getPOA()->id_to_reference(id));
191   Engines::ContainerScriptPerfLog_var scriptPtr2 = Engines::ContainerScriptPerfLog::_narrow(scriptPtr);
192   _scripts.push_back( scriptPtr2 );
193   {
194     AutoGIL gstate;
195     PyObject *result = PyObject_CallMethod(pyObj(),(char*)"addScript","",nullptr);
196     if (PyErr_Occurred())
197     {
198       std::string error("can not addScript");
199       PyErr_Print();
200       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
201     }
202     script->setPyObj( result );
203   }
204   return scriptPtr2._retn();
205 }
206
207 Engines::ListOfContainerScriptPerfLog *SALOME_ContainerPerfLog::listOfScripts()
208 {
209   Engines::ListOfContainerScriptPerfLog_var ret = new Engines::ListOfContainerScriptPerfLog;
210   std::size_t len( this->_scripts.size() );
211   ret->length( len );
212   for(std::size_t i = 0 ; i < len ; ++i)
213     ret[i] = this->_scripts[i];
214   return ret._retn();
215 }
216
217 void SALOME_ContainerPerfLog::accept(SALOME_VisitorContainerLog &visitor)
218 {
219   visitor.enterContainerPerfLog( *this );
220   for(auto script : _scripts)
221   {
222     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( script );
223     serv->_remove_ref();
224     SALOME_ContainerScriptPerfLog *servC = dynamic_cast<SALOME_ContainerScriptPerfLog *>(serv);
225     servC->accept(visitor);
226   }
227   visitor.leaveContainerPerfLog( *this );
228 }
229
230 char *SALOME_ContainerPerfLog::getLogFile()
231 {
232   return CORBA::string_dup( this->_log_file.c_str() );
233 }
234
235 char *SALOME_ContainerPerfLog::getContainerEntryInNS()
236 {
237   return CORBA::string_dup( this->_name_in_ns.c_str() );
238 }
239
240 /////
241
242 std::string SALOME_SafeLoggerFileHolder::getLastVersionOfFileNameLogger()
243 {
244   switch( _version_activated )
245   {
246   case SafeLoggerActiveVersionType::VersionA_Activated:
247     return _logger_file_a;
248   case SafeLoggerActiveVersionType::VersionB_Activated:
249     return _logger_file_b;
250   case SafeLoggerActiveVersionType::NoVersion_Activated:
251     return std::string();
252   default:
253     throw std::runtime_error("getLastVersionOfFileNameLogger : Situation not managed");
254   }
255 }
256
257 /////
258
259 SALOME_LogManager::SALOME_LogManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa,SALOME_NamingService_Abstract *ns):_poa(poa)
260 {
261   _NS.reset(ns);
262   PortableServer::ObjectId_var id(_poa->activate_object(this));
263   CORBA::Object_var obj(_poa->id_to_reference(id));
264   Engines::LogManager_var refPtr(Engines::LogManager::_narrow(obj));
265   _NS->Register(refPtr,NAME_IN_NS);
266   {
267     AutoGIL gstate;
268     std::ostringstream myCommand;
269     myCommand << "mylogmanager = SALOME_LogManager.SALOME_LogManagerHelper()";
270     PyRun_SimpleString("import SALOME_LogManager");
271     PyRun_SimpleString((char*)myCommand.str().c_str());
272     PyObject *mainmod = PyImport_AddModule("__main__");
273     PyObject *globals = PyModule_GetDict(mainmod);
274     _pyLogManager = PyDict_GetItemString(globals, "mylogmanager");
275   }
276 }
277
278 Engines::ContainerPerfLog_ptr SALOME_LogManager::declareContainer(const char *contInNS, const char *logfile)
279 {
280   SALOME_ContainerPerfLog *cont = new SALOME_ContainerPerfLog(this,contInNS,logfile);
281   PortableServer::ObjectId_var id(_poa->activate_object(cont));
282   CORBA::Object_var contPtr(_poa->id_to_reference(id));
283   cont->_remove_ref();
284   Engines::ContainerPerfLog_var contPtr2 = Engines::ContainerPerfLog::_narrow(contPtr);
285   _containers.push_back( contPtr2 );
286   {
287     AutoGIL gstate;
288     PyObject *result = PyObject_CallMethod(_pyLogManager,(char*)"declareContainer","ss",contInNS,logfile,nullptr);
289     if (PyErr_Occurred())
290     {
291       std::string error("can not declareContainer");
292       PyErr_Print();
293       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
294     }
295     cont->setPyObj( result );
296   }
297   return contPtr2._retn();
298 }
299
300 Engines::ListOfContainerPerfLog *SALOME_LogManager::listOfContainerLogs()
301 {
302   Engines::ListOfContainerPerfLog_var ret = new Engines::ListOfContainerPerfLog;
303   std::size_t len( this->_containers.size() );
304   ret->length( len );
305   for(std::size_t i = 0 ; i < len ; ++i)
306   {
307     ret[i] = this->_containers[i];
308   }
309   return ret._retn();
310 }
311
312 void SALOME_LogManager::accept(SALOME_VisitorContainerLog &visitor)
313 {
314   visitor.enterLogManager( *this );
315   for(auto container : _containers)
316   {
317     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( container );
318     serv->_remove_ref();
319     SALOME_ContainerPerfLog *servC = dynamic_cast<SALOME_ContainerPerfLog *>(serv);
320     servC->accept(visitor);
321   }
322   visitor.leaveLogManager( *this );
323 }
324
325 /*!
326   \param [in] unloadMemory - specify if big part of struct data (SALOME_ContainerScriptExecPerfLog) is cleared after retrieving data
327  */
328 SALOME::vectorOfByte *SALOME_LogManager::getAllStruct(bool clearMemory)
329 {
330   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
331   return FromVectCharToCorba(data);
332 }
333
334 void SALOME_LogManager::putStructInFileAtomic(bool clearMemory, const char *fileName)
335 {
336   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
337   {
338     AutoGIL gstate;
339     AutoPyRef dataPy(PyBytes_FromStringAndSize(data.data(),data.size()));
340     AutoPyRef result = PyObject_CallMethod(_pyLogManager,(char*)"putStructInFileAtomic","Os",dataPy.get(),fileName,nullptr);
341   }
342 }
343
344 void SALOME_LogManager::setFileNamePairOfLogger(const char *loggerFileNameA, const char *loggerFileNameB)
345 {
346   _safe_logger_file_holder.setFileNamePairOfLogger(loggerFileNameA,loggerFileNameB);
347 }
348
349 void SALOME_LogManager::getFileNamePairOfLogger(CORBA::String_out loggerFileNameA, CORBA::String_out loggerFileNameB)
350 {
351   std::string loggerFileNameAS,loggerFileNameBS;
352   _safe_logger_file_holder.getFileNamePairOfLogger(loggerFileNameAS,loggerFileNameBS);
353   loggerFileNameA = CORBA::string_dup(loggerFileNameAS.c_str());
354   loggerFileNameB = CORBA::string_dup(loggerFileNameBS.c_str());
355 }
356
357 char *SALOME_LogManager::getLastVersionOfFileNameLogger()
358 {
359   return CORBA::string_dup( _safe_logger_file_holder.getLastVersionOfFileNameLogger().c_str() );
360 }
361
362 ///////////////////////
363  
364  #include <cstdint>
365
366 static void PushIntInVC(std::uint32_t val, std::vector<char>& data)
367 {
368   char *valPtr = reinterpret_cast<char *>(&val);
369   data.insert(data.end(),valPtr,valPtr+sizeof(std::uint32_t));
370 }
371  
372 template<class T>
373 static void PushStringInVC(const T& str, std::vector<char>& data)
374 {
375   std::uint32_t sz = static_cast<std::uint32_t>( str.size() );
376   PushIntInVC(sz,data);
377   data.insert(data.end(),str.data(),str.data()+sz);
378 }
379
380 class InternalFormatVisitorDump : public SALOME_VisitorContainerLog
381 {
382 public:
383   InternalFormatVisitorDump(bool clearMemory, std::vector<char> *data):_clear_memory(clearMemory),_data(data) { }
384   void enterLogManager(SALOME_LogManager& inst) override;
385   void leaveLogManager(SALOME_LogManager& inst) override { }
386   void enterContainerPerfLog(SALOME_ContainerPerfLog& inst) override;
387   void leaveContainerPerfLog(SALOME_ContainerPerfLog& inst) override { }
388   void enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override;
389   void leaveContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override { }
390   void visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst) override;
391 private:
392   bool _clear_memory = false;
393   std::vector<char> *_data = nullptr;
394 };
395
396 void InternalFormatVisitorDump::visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst)
397 {
398   PushStringInVC<std::vector<char>>(inst.data(),*_data);
399   if( _clear_memory )
400     inst.clear();
401 }
402
403 void InternalFormatVisitorDump::enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst)
404 {
405   PushStringInVC<std::string>(inst.name(),*_data);
406   PushStringInVC<std::string>(inst.code(),*_data);
407   PushIntInVC((std::uint32_t)inst.getNumberOfSessions(),*_data);
408 }
409
410 void InternalFormatVisitorDump::enterContainerPerfLog(SALOME_ContainerPerfLog& inst)
411 {
412   PushStringInVC<std::string>(inst.nameInNS(),*_data);
413   PushStringInVC<std::string>(inst.logFile(),*_data);
414   PushIntInVC((std::uint32_t)inst.getNumberOfScripts(),*_data);
415 }
416
417 void InternalFormatVisitorDump::enterLogManager(SALOME_LogManager& inst)
418 {
419   PushIntInVC((std::uint32_t)inst.getNumberOfContainers(),*_data);
420 }
421
422 std::vector<char> SALOME_LogManager::dumpCppInternalFrmt(bool clearMemory)
423 {
424   std::vector<char> ret;
425   InternalFormatVisitorDump visitor(clearMemory,&ret);
426   this->accept( visitor );
427   return ret;
428 }