Salome HOME
6e106965e835104b7ae92f6cfb31f7ed0f068e41
[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   for(auto script : _scripts)
197   {
198     PortableServer::ServantBase *serv = getPOA()->reference_to_servant(script);
199     PortableServer::ObjectId_var oid = getPOA()->reference_to_id(script);
200     getPOA()->deactivate_object(oid);
201   }
202   _scripts.clear();
203 }
204
205 PortableServer::POA_var SALOME_ContainerPerfLog::getPOA()
206 {
207   return father()->getPOA();
208   }
209
210 Engines::ContainerScriptPerfLog_ptr SALOME_ContainerPerfLog::addScript(const char *name, const char *code)
211 {
212   SALOME_ContainerScriptPerfLog *script = new SALOME_ContainerScriptPerfLog(this,name,code);
213   PortableServer::ObjectId_var id(getPOA()->activate_object(script));
214   script->_remove_ref();
215   CORBA::Object_var scriptPtr(getPOA()->id_to_reference(id));
216   Engines::ContainerScriptPerfLog_var scriptPtr2 = Engines::ContainerScriptPerfLog::_narrow(scriptPtr);
217   _scripts.push_back( scriptPtr2 );
218   {
219     AutoGIL gstate;
220     PyObject *result = PyObject_CallMethod(pyObj(),(char*)"addScript","",nullptr);
221     if (PyErr_Occurred())
222     {
223       std::string error("can not addScript");
224       PyErr_Print();
225       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
226     }
227     script->setPyObj( result );
228   }
229   return scriptPtr2._retn();
230 }
231
232 Engines::ListOfContainerScriptPerfLog *SALOME_ContainerPerfLog::listOfScripts()
233 {
234   Engines::ListOfContainerScriptPerfLog_var ret = new Engines::ListOfContainerScriptPerfLog;
235   std::size_t len( this->_scripts.size() );
236   ret->length( len );
237   for(std::size_t i = 0 ; i < len ; ++i)
238     ret[i] = this->_scripts[i];
239   return ret._retn();
240 }
241
242 void SALOME_ContainerPerfLog::accept(SALOME_VisitorContainerLog &visitor)
243 {
244   visitor.enterContainerPerfLog( *this );
245   for(auto script : _scripts)
246   {
247     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( script );
248     serv->_remove_ref();
249     SALOME_ContainerScriptPerfLog *servC = dynamic_cast<SALOME_ContainerScriptPerfLog *>(serv);
250     servC->accept(visitor);
251   }
252   visitor.leaveContainerPerfLog( *this );
253 }
254
255 char *SALOME_ContainerPerfLog::getLogFile()
256 {
257   return CORBA::string_dup( this->_log_file.c_str() );
258 }
259
260 char *SALOME_ContainerPerfLog::getContainerEntryInNS()
261 {
262   return CORBA::string_dup( this->_name_in_ns.c_str() );
263 }
264
265 /////
266
267 std::string SALOME_SafeLoggerFileHolder::getLastVersionOfFileNameLogger()
268 {
269   switch( _version_activated )
270   {
271   case SafeLoggerActiveVersionType::VersionA_Activated:
272     return _logger_file_a;
273   case SafeLoggerActiveVersionType::VersionB_Activated:
274     return _logger_file_b;
275   case SafeLoggerActiveVersionType::NoVersion_Activated:
276     return std::string();
277   default:
278     throw std::runtime_error("getLastVersionOfFileNameLogger : Situation not managed");
279   }
280 }
281
282 /////
283
284 SALOME_LogManager::SALOME_LogManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa,SALOME_NamingService_Abstract *ns):_poa(poa)
285 {
286   _NS.reset(ns);
287   PortableServer::ObjectId_var id(_poa->activate_object(this));
288   CORBA::Object_var obj(_poa->id_to_reference(id));
289   Engines::LogManager_var refPtr(Engines::LogManager::_narrow(obj));
290   _NS->Register(refPtr,NAME_IN_NS);
291   {
292     AutoGIL gstate;
293     std::ostringstream myCommand;
294     myCommand << "mylogmanager = SALOME_LogManager.SALOME_LogManagerHelper()";
295     PyRun_SimpleString("import SALOME_LogManager");
296     PyRun_SimpleString((char*)myCommand.str().c_str());
297     PyObject *mainmod = PyImport_AddModule("__main__");
298     PyObject *globals = PyModule_GetDict(mainmod);
299     _pyLogManager = PyDict_GetItemString(globals, "mylogmanager");
300   }
301 }
302
303 SALOME_LogManager::~SALOME_LogManager()
304 {
305   this->clear();
306 }
307
308 void SALOME_LogManager::clear()
309 {
310   for(auto cont : _containers)
311   {
312     PortableServer::ServantBase *serv = getPOA()->reference_to_servant(cont);
313     PortableServer::ObjectId_var oid = getPOA()->reference_to_id(cont);
314     getPOA()->deactivate_object(oid);
315   }
316   _containers.clear();
317 }
318
319 Engines::ContainerPerfLog_ptr SALOME_LogManager::declareContainer(const char *contInNS, const char *logfile)
320 {
321   SALOME_ContainerPerfLog *cont = new SALOME_ContainerPerfLog(this,contInNS,logfile);
322   PortableServer::ObjectId_var id(_poa->activate_object(cont));
323   CORBA::Object_var contPtr(_poa->id_to_reference(id));
324   cont->_remove_ref();
325   Engines::ContainerPerfLog_var contPtr2 = Engines::ContainerPerfLog::_narrow(contPtr);
326   _containers.push_back( contPtr2 );
327   {
328     AutoGIL gstate;
329     PyObject *result = PyObject_CallMethod(_pyLogManager,(char*)"declareContainer","ss",contInNS,logfile,nullptr);
330     if (PyErr_Occurred())
331     {
332       std::string error("can not declareContainer");
333       PyErr_Print();
334       THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
335     }
336     cont->setPyObj( result );
337   }
338   return contPtr2._retn();
339 }
340
341 Engines::ListOfContainerPerfLog *SALOME_LogManager::listOfContainerLogs()
342 {
343   Engines::ListOfContainerPerfLog_var ret = new Engines::ListOfContainerPerfLog;
344   std::size_t len( this->_containers.size() );
345   ret->length( len );
346   for(std::size_t i = 0 ; i < len ; ++i)
347   {
348     ret[i] = this->_containers[i];
349   }
350   return ret._retn();
351 }
352
353 void SALOME_LogManager::accept(SALOME_VisitorContainerLog &visitor)
354 {
355   visitor.enterLogManager( *this );
356   for(auto container : _containers)
357   {
358     PortableServer::ServantBase *serv = getPOA()->reference_to_servant( container );
359     serv->_remove_ref();
360     SALOME_ContainerPerfLog *servC = dynamic_cast<SALOME_ContainerPerfLog *>(serv);
361     servC->accept(visitor);
362   }
363   visitor.leaveLogManager( *this );
364 }
365
366 /*!
367   \param [in] unloadMemory - specify if big part of struct data (SALOME_ContainerScriptExecPerfLog) is cleared after retrieving data
368  */
369 SALOME::vectorOfByte *SALOME_LogManager::getAllStruct(bool clearMemory)
370 {
371   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
372   return FromVectCharToCorba(data);
373 }
374
375 void SALOME_LogManager::putStructInFileAtomic(bool clearMemory, const char *fileName)
376 {
377   std::vector<char> data = this->dumpCppInternalFrmt(clearMemory);
378   {
379     AutoGIL gstate;
380     AutoPyRef dataPy(PyBytes_FromStringAndSize(data.data(),data.size()));
381     AutoPyRef result = PyObject_CallMethod(_pyLogManager,(char*)"putStructInFileAtomic","Os",dataPy.get(),fileName,nullptr);
382   }
383 }
384
385 void SALOME_LogManager::setFileNamePairOfLogger(const char *loggerFileNameA, const char *loggerFileNameB)
386 {
387   _safe_logger_file_holder.setFileNamePairOfLogger(loggerFileNameA,loggerFileNameB);
388 }
389
390 void SALOME_LogManager::getFileNamePairOfLogger(CORBA::String_out loggerFileNameA, CORBA::String_out loggerFileNameB)
391 {
392   std::string loggerFileNameAS,loggerFileNameBS;
393   _safe_logger_file_holder.getFileNamePairOfLogger(loggerFileNameAS,loggerFileNameBS);
394   loggerFileNameA = CORBA::string_dup(loggerFileNameAS.c_str());
395   loggerFileNameB = CORBA::string_dup(loggerFileNameBS.c_str());
396 }
397
398 char *SALOME_LogManager::getLastVersionOfFileNameLogger()
399 {
400   return CORBA::string_dup( _safe_logger_file_holder.getLastVersionOfFileNameLogger().c_str() );
401 }
402
403 ///////////////////////
404  
405  #include <cstdint>
406
407 static void PushIntInVC(std::uint32_t val, std::vector<char>& data)
408 {
409   char *valPtr = reinterpret_cast<char *>(&val);
410   data.insert(data.end(),valPtr,valPtr+sizeof(std::uint32_t));
411 }
412  
413 template<class T>
414 static void PushStringInVC(const T& str, std::vector<char>& data)
415 {
416   std::uint32_t sz = static_cast<std::uint32_t>( str.size() );
417   PushIntInVC(sz,data);
418   data.insert(data.end(),str.data(),str.data()+sz);
419 }
420
421 class InternalFormatVisitorDump : public SALOME_VisitorContainerLog
422 {
423 public:
424   InternalFormatVisitorDump(bool clearMemory, std::vector<char> *data):_clear_memory(clearMemory),_data(data) { }
425   void enterLogManager(SALOME_LogManager& inst) override;
426   void leaveLogManager(SALOME_LogManager& inst) override { }
427   void enterContainerPerfLog(SALOME_ContainerPerfLog& inst) override;
428   void leaveContainerPerfLog(SALOME_ContainerPerfLog& inst) override { }
429   void enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override;
430   void leaveContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst) override { }
431   void visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst) override;
432 private:
433   bool _clear_memory = false;
434   std::vector<char> *_data = nullptr;
435 };
436
437 void InternalFormatVisitorDump::visitContainerScriptExecPerfLog(SALOME_ContainerScriptExecPerfLog& inst)
438 {
439   PushStringInVC<std::vector<char>>(inst.data(),*_data);
440   if( _clear_memory )
441     inst.clear();
442 }
443
444 void InternalFormatVisitorDump::enterContainerScriptPerfLog(SALOME_ContainerScriptPerfLog& inst)
445 {
446   PushStringInVC<std::string>(inst.name(),*_data);
447   PushStringInVC<std::string>(inst.code(),*_data);
448   PushIntInVC((std::uint32_t)inst.getNumberOfSessions(),*_data);
449 }
450
451 void InternalFormatVisitorDump::enterContainerPerfLog(SALOME_ContainerPerfLog& inst)
452 {
453   PushStringInVC<std::string>(inst.nameInNS(),*_data);
454   PushStringInVC<std::string>(inst.logFile(),*_data);
455   PushIntInVC((std::uint32_t)inst.getNumberOfScripts(),*_data);
456 }
457
458 void InternalFormatVisitorDump::enterLogManager(SALOME_LogManager& inst)
459 {
460   PushIntInVC((std::uint32_t)inst.getNumberOfContainers(),*_data);
461 }
462
463 std::vector<char> SALOME_LogManager::dumpCppInternalFrmt(bool clearMemory)
464 {
465   std::vector<char> ret;
466   InternalFormatVisitorDump visitor(clearMemory,&ret);
467   this->accept( visitor );
468   return ret;
469 }