Salome HOME
f336d56a22c29e7c2b25c8ccbe7238aa4cb68eff
[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 "utilities.h"
32
33 #include <sstream>
34 #include <fstream>
35 #include <algorithm>
36 #include <memory>
37 #include <functional>
38
39 const char SALOME_LogManager::NAME_IN_NS[]="/LogManager";
40
41 static std::vector<char> FromPyToCpp(PyObject *obj)
42 {
43   std::vector<char> ret;
44   char *buffer = nullptr;
45   Py_ssize_t length = 0;
46   PyBytes_AsStringAndSize(obj,&buffer,&length);
47   ret.resize(length);
48   for(auto i = 0 ; i < length ; ++i)
49     ret[i] = buffer[i];
50   return ret;
51 }
52
53 static SALOME::vectorOfByte *FromVectCharToCorba(const std::vector<char>& data)
54 {
55   SALOME::vectorOfByte_var ret = new SALOME::vectorOfByte;
56   auto length = data.size();
57   ret->length(length);
58   for(auto i = 0 ; i < length ; ++i)
59     ret[i] = data[i];
60   return ret._retn();
61 }
62
63 SALOME_ContainerScriptPerfLog::~SALOME_ContainerScriptPerfLog()
64 {
65   for(auto execSession : _sessions)
66   {
67     PortableServer::ServantBase *serv = getPOA()->reference_to_servant(execSession);
68     PortableServer::ObjectId_var oid = getPOA()->reference_to_id(execSession);
69     getPOA()->deactivate_object(oid);
70   }
71   _sessions.clear();
72 }
73
74 PortableServer::POA_var SALOME_ContainerScriptExecPerfLog::getPOA()
75 {
76   return father()->getPOA();
77 }
78
79 void SALOME_ContainerScriptExecPerfLog::assign(const SALOME::vectorOfByte& value)
80 {
81   auto sz = value.length();
82   _data.resize( sz );
83   for(auto i = 0 ; i < sz ; ++i)
84     _data[i] = value[i];
85   //
86   AutoPyRef s( this->end( ) );
87   //
88   _data = FromPyToCpp(s);
89 }
90
91 SALOME::vectorOfByte *SALOME_ContainerScriptExecPerfLog::getObj()
92 {
93   return FromVectCharToCorba(this->_data);
94 }
95
96 void SALOME_ContainerScriptExecPerfLog::accept(SALOME_VisitorContainerLog &visitor)
97 {
98   visitor.visitContainerScriptExecPerfLog( *this );
99 }
100
101 void SALOME_ContainerScriptExecPerfLog::start()
102 {
103   AutoGIL gstate;
104   AutoPyRef result = PyObject_CallMethod(pyObj(),(char*)"start","",nullptr);
105   if (PyErr_Occurred())
106   {
107     std::string error("can not start");
108     PyErr_Print();
109     THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
110   }
111 }
112
113 AutoPyRef SALOME_ContainerScriptExecPerfLog::end()
114 {
115   AutoGIL gstate;
116   //https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue
117   AutoPyRef dataPy(PyBytes_FromStringAndSize(_data.data(),_data.size()));
118   AutoPyRef result(PyObject_CallMethod(pyObj(),(char*)"end","O",dataPy.get(),nullptr) ) ;
119   if (PyErr_Occurred())
120   {
121     std::string error("can not end");
122     PyErr_Print();
123     THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
124   }
125   return result;
126 }
127
128 /////
129
130 PortableServer::POA_var SALOME_ContainerScriptPerfLog::getPOA()
131 {
132   return father()->getPOA();
133 }
134
135 char *SALOME_ContainerScriptPerfLog::getCode()
136 {
137   return CORBA::string_dup( _code.c_str() );
138 }
139
140 char *SALOME_ContainerScriptPerfLog::getName()
141 {
142   return CORBA::string_dup( _name.c_str() );
143 }
144
145 void SALOME_ContainerScriptPerfLog::accept(SALOME_VisitorContainerLog &visitor)
146 {
147   visitor.enterContainerScriptPerfLog( *this );
148   for(auto session : _sessions)
149   {
150     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( session );
151     serv->_remove_ref();
152     SALOME_ContainerScriptExecPerfLog *servC = dynamic_cast<SALOME_ContainerScriptExecPerfLog *>(serv);
153     visitor.visitContainerScriptExecPerfLog( *servC );
154   }
155   visitor.leaveContainerScriptPerfLog( *this );
156 }
157
158
159 Engines::ContainerScriptExecPerfLog_ptr SALOME_ContainerScriptPerfLog::addExecutionSession()
160 {
161   SALOME_ContainerScriptExecPerfLog *execution = new SALOME_ContainerScriptExecPerfLog(this);
162   PortableServer::ObjectId_var id(getPOA()->activate_object(execution));
163   execution->_remove_ref();
164   CORBA::Object_var executionPtr(getPOA()->id_to_reference(id));
165   Engines::ContainerScriptExecPerfLog_var executionPtr2 = Engines::ContainerScriptExecPerfLog::_narrow(executionPtr);
166   _sessions.push_back( executionPtr2 );
167   {
168     AutoGIL gstate;
169     AutoPyRef result = PyObject_CallMethod(pyObj(),(char*)"addExecution","",nullptr);
170     if (PyErr_Occurred())
171     {
172       std::string error("can not addExecution");
173       PyErr_Print();
174       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
175     }
176     execution->setPyObj( result.retn() );//ownership of result is transfered to execution
177   }
178   execution->start();
179   return executionPtr2._retn();
180 }
181
182 Engines::ListOfContainerScriptExecPerfLog *SALOME_ContainerScriptPerfLog::listOfExecs()
183 {
184   Engines::ListOfContainerScriptExecPerfLog_var ret = new Engines::ListOfContainerScriptExecPerfLog;
185   auto sz = this->_sessions.size();
186   ret->length(sz);
187   for(auto i = 0 ; i < sz ; ++i)
188     ret[i] = this->_sessions[i];
189   return ret._retn();
190 }
191
192 /////
193
194 SALOME_ContainerPerfLog::~SALOME_ContainerPerfLog()
195 {
196   this->destroyInternal();
197 }
198
199 PortableServer::POA_var SALOME_ContainerPerfLog::getPOA()
200 {
201   return father()->getPOA();
202   }
203
204 Engines::ContainerScriptPerfLog_ptr SALOME_ContainerPerfLog::addScript(const char *name, const char *code)
205 {
206   SALOME_ContainerScriptPerfLog *script = new SALOME_ContainerScriptPerfLog(this,name,code);
207   PortableServer::ObjectId_var id(getPOA()->activate_object(script));
208   script->_remove_ref();
209   CORBA::Object_var scriptPtr(getPOA()->id_to_reference(id));
210   Engines::ContainerScriptPerfLog_var scriptPtr2 = Engines::ContainerScriptPerfLog::_narrow(scriptPtr);
211   _scripts.push_back( scriptPtr2 );
212   {
213     AutoGIL gstate;
214     PyObject *result = PyObject_CallMethod(pyObj(),(char*)"addScript","",nullptr);
215     if (PyErr_Occurred())
216     {
217       std::string error("can not addScript");
218       PyErr_Print();
219       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
220     }
221     script->setPyObj( result );
222   }
223   return scriptPtr2._retn();
224 }
225
226 Engines::ListOfContainerScriptPerfLog *SALOME_ContainerPerfLog::listOfScripts()
227 {
228   Engines::ListOfContainerScriptPerfLog_var ret = new Engines::ListOfContainerScriptPerfLog;
229   std::size_t len( this->_scripts.size() );
230   ret->length( len );
231   for(std::size_t i = 0 ; i < len ; ++i)
232     ret[i] = this->_scripts[i];
233   return ret._retn();
234 }
235
236 void SALOME_ContainerPerfLog::destroy()
237 {
238   this->destroyInternal();
239 }
240
241 void SALOME_ContainerPerfLog::destroyInternal()
242 {
243   _father->removeEntryBeforeDying( this );
244   for(auto script : _scripts)
245   {
246     PortableServer::ServantBase *serv = getPOA()->reference_to_servant(script);
247     PortableServer::ObjectId_var oid = getPOA()->reference_to_id(script);
248     getPOA()->deactivate_object(oid);
249   }
250   _scripts.clear();
251 }
252
253 void SALOME_ContainerPerfLog::accept(SALOME_VisitorContainerLog &visitor)
254 {
255   visitor.enterContainerPerfLog( *this );
256   for(auto script : _scripts)
257   {
258     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( script );
259     serv->_remove_ref();
260     SALOME_ContainerScriptPerfLog *servC = dynamic_cast<SALOME_ContainerScriptPerfLog *>(serv);
261     servC->accept(visitor);
262   }
263   visitor.leaveContainerPerfLog( *this );
264 }
265
266 char *SALOME_ContainerPerfLog::getLogFile()
267 {
268   return CORBA::string_dup( this->_log_file.c_str() );
269 }
270
271 char *SALOME_ContainerPerfLog::getContainerEntryInNS()
272 {
273   return CORBA::string_dup( this->_name_in_ns.c_str() );
274 }
275
276 /////
277
278 std::string SALOME_SafeLoggerFileHolder::getLastVersionOfFileNameLogger()
279 {
280   switch( _version_activated )
281   {
282   case SafeLoggerActiveVersionType::VersionA_Activated:
283     return _logger_file_a;
284   case SafeLoggerActiveVersionType::VersionB_Activated:
285     return _logger_file_b;
286   case SafeLoggerActiveVersionType::NoVersion_Activated:
287     return std::string();
288   default:
289     throw std::runtime_error("getLastVersionOfFileNameLogger : Situation not managed");
290   }
291 }
292
293 /////
294
295 SALOME_LogManager::SALOME_LogManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa,SALOME_NamingService_Abstract *ns):_poa(poa)
296 {
297   _NS.reset(ns);
298   PortableServer::ObjectId_var id(_poa->activate_object(this));
299   CORBA::Object_var obj(_poa->id_to_reference(id));
300   Engines::LogManager_var refPtr(Engines::LogManager::_narrow(obj));
301   _NS->Register(refPtr,NAME_IN_NS);
302   {
303     AutoGIL gstate;
304     std::ostringstream myCommand;
305     myCommand << "mylogmanager = SALOME_LogManager.SALOME_LogManagerHelper()";
306     PyRun_SimpleString("import SALOME_LogManager");
307     PyRun_SimpleString((char*)myCommand.str().c_str());
308     PyObject *mainmod = PyImport_AddModule("__main__");
309     PyObject *globals = PyModule_GetDict(mainmod);
310     _pyLogManager = PyDict_GetItemString(globals, "mylogmanager");
311   }
312 }
313
314 SALOME_LogManager::~SALOME_LogManager()
315 {
316   this->clear();
317 }
318
319 void SALOME_LogManager::clear()
320 {
321   for(auto cont : _containers)
322   {
323     PortableServer::ServantBase *serv = getPOA()->reference_to_servant(cont);
324     PortableServer::ObjectId_var oid = getPOA()->reference_to_id(cont);
325     getPOA()->deactivate_object(oid);
326   }
327   _containers.clear();
328 }
329
330 Engines::ContainerPerfLog_ptr SALOME_LogManager::declareContainer(const char *contInNS, const char *logfile)
331 {
332   SALOME_ContainerPerfLog *cont = new SALOME_ContainerPerfLog(this,contInNS,logfile);
333   PortableServer::ObjectId_var id(_poa->activate_object(cont));
334   CORBA::Object_var contPtr(_poa->id_to_reference(id));
335   cont->_remove_ref();
336   Engines::ContainerPerfLog_var contPtr2 = Engines::ContainerPerfLog::_narrow(contPtr);
337   _containers.push_back( contPtr2 );
338   {
339     AutoGIL gstate;
340     PyObject *result = PyObject_CallMethod(_pyLogManager,(char*)"declareContainer","ss",contInNS,logfile,nullptr);
341     if (PyErr_Occurred())
342     {
343       std::string error("can not declareContainer");
344       PyErr_Print();
345       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
346     }
347     cont->setPyObj( result );
348   }
349   return contPtr2._retn();
350 }
351
352 Engines::ListOfContainerPerfLog *SALOME_LogManager::listOfContainerLogs()
353 {
354   Engines::ListOfContainerPerfLog_var ret = new Engines::ListOfContainerPerfLog;
355   std::size_t len( this->_containers.size() );
356   ret->length( len );
357   for(std::size_t i = 0 ; i < len ; ++i)
358   {
359     ret[i] = this->_containers[i];
360   }
361   return ret._retn();
362 }
363
364 void SALOME_LogManager::accept(SALOME_VisitorContainerLog &visitor)
365 {
366   visitor.enterLogManager( *this );
367   for(auto container : _containers)
368   {
369     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( container );
370     serv->_remove_ref();
371     SALOME_ContainerPerfLog *servC = dynamic_cast<SALOME_ContainerPerfLog *>(serv);
372     servC->accept(visitor);
373   }
374   visitor.leaveLogManager( *this );
375 }
376
377 /*!
378   \param [in] unloadMemory - specify if big part of struct data (SALOME_ContainerScriptExecPerfLog) is cleared after retrieving data
379  */
380 SALOME::vectorOfByte *SALOME_LogManager::getAllStruct(bool clearMemory)
381 {
382   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
383   return FromVectCharToCorba(data);
384 }
385
386 void SALOME_LogManager::putStructInFileAtomic(bool clearMemory, const char *fileName)
387 {
388   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
389   {
390     AutoGIL gstate;
391     AutoPyRef dataPy(PyBytes_FromStringAndSize(data.data(),data.size()));
392     AutoPyRef result = PyObject_CallMethod(_pyLogManager,(char*)"putStructInFileAtomic","Os",dataPy.get(),fileName,nullptr);
393   }
394 }
395
396 void SALOME_LogManager::setFileNamePairOfLogger(const char *loggerFileNameA, const char *loggerFileNameB)
397 {
398   _safe_logger_file_holder.setFileNamePairOfLogger(loggerFileNameA,loggerFileNameB);
399 }
400
401 void SALOME_LogManager::getFileNamePairOfLogger(CORBA::String_out loggerFileNameA, CORBA::String_out loggerFileNameB)
402 {
403   std::string loggerFileNameAS,loggerFileNameBS;
404   _safe_logger_file_holder.getFileNamePairOfLogger(loggerFileNameAS,loggerFileNameBS);
405   loggerFileNameA = CORBA::string_dup(loggerFileNameAS.c_str());
406   loggerFileNameB = CORBA::string_dup(loggerFileNameBS.c_str());
407 }
408
409 char *SALOME_LogManager::getLastVersionOfFileNameLogger()
410 {
411   return CORBA::string_dup( _safe_logger_file_holder.getLastVersionOfFileNameLogger().c_str() );
412 }
413
414 void SALOME_LogManager::removeEntryBeforeDying(SALOME_ContainerPerfLog *child)
415 {
416   for(auto cont = _containers.begin() ; cont != _containers.end() ; ++cont )
417   {
418     PortableServer::ServantBase *serv = getPOA()->reference_to_servant(*cont);
419     SALOME_ContainerPerfLog *servCand = dynamic_cast<SALOME_ContainerPerfLog *>(serv);
420     if( servCand==child )
421       {
422         _containers.erase( cont );
423         break;
424       }
425   }
426 }
427
428 ///////////////////////
429  
430  #include <cstdint>
431
432 static void PushIntInVC(std::uint32_t val, std::vector<char>& data)
433 {
434   char *valPtr = reinterpret_cast<char *>(&val);
435   data.insert(data.end(),valPtr,valPtr+sizeof(std::uint32_t));
436 }
437  
438 template<class T>
439 static void PushStringInVC(const T& str, std::vector<char>& data)
440 {
441   std::uint32_t sz = static_cast<std::uint32_t>( str.size() );
442   PushIntInVC(sz,data);
443   data.insert(data.end(),str.data(),str.data()+sz);
444 }
445
446 class InternalFormatVisitorDump : public SALOME_VisitorContainerLog
447 {
448 public:
449   InternalFormatVisitorDump(bool clearMemory, std::vector<char> *data):_clear_memory(clearMemory),_data(data) { }
450   void enterLogManager(SALOME_LogManager& inst) override;
451   void leaveLogManager(SALOME_LogManager& inst) override { }
452   void enterContainerPerfLog(SALOME_ContainerPerfLog& inst) override;
453   void leaveContainerPerfLog(SALOME_ContainerPerfLog& inst) override { }
454   void enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override;
455   void leaveContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override { }
456   void visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst) override;
457 private:
458   bool _clear_memory = false;
459   std::vector<char> *_data = nullptr;
460 };
461
462 void InternalFormatVisitorDump::visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst)
463 {
464   PushStringInVC<std::vector<char>>(inst.data(),*_data);
465   if( _clear_memory )
466     inst.clear();
467 }
468
469 void InternalFormatVisitorDump::enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst)
470 {
471   PushStringInVC<std::string>(inst.name(),*_data);
472   PushStringInVC<std::string>(inst.code(),*_data);
473   PushIntInVC((std::uint32_t)inst.getNumberOfSessions(),*_data);
474 }
475
476 void InternalFormatVisitorDump::enterContainerPerfLog(SALOME_ContainerPerfLog& inst)
477 {
478   PushStringInVC<std::string>(inst.nameInNS(),*_data);
479   PushStringInVC<std::string>(inst.logFile(),*_data);
480   PushIntInVC((std::uint32_t)inst.getNumberOfScripts(),*_data);
481 }
482
483 void InternalFormatVisitorDump::enterLogManager(SALOME_LogManager& inst)
484 {
485   PushIntInVC((std::uint32_t)inst.getNumberOfContainers(),*_data);
486 }
487
488 std::vector<char> SALOME_LogManager::dumpCppInternalFrmt(bool clearMemory)
489 {
490   std::vector<char> ret;
491   InternalFormatVisitorDump visitor(clearMemory,&ret);
492   this->accept( visitor );
493   return ret;
494 }