From a19cbfecc3422abd583934479c60bc4a834c4a8d Mon Sep 17 00:00:00 2001 From: nds Date: Wed, 12 Feb 2020 23:41:59 +0300 Subject: [PATCH] 0029451: Information Message Alert to debug an algorithm or object functionality (cherry picked from commit f36aa84ef8e8efa1ed6d12efabce1d4e6de940d1) --- src/DDocStd/DDocStd_ToolsCommands.cxx | 22 ++ src/Draw/Draw_BasicCommands.cxx | 116 ++++++ src/Message/FILES | 20 +- src/Message/Message.cxx | 116 +++++- src/Message/Message.hxx | 55 ++- src/Message/Message_Alert.hxx | 1 - src/Message/Message_AlertExtended.cxx | 91 +++++ src/Message/Message_AlertExtended.hxx | 89 +++++ src/Message/Message_Attribute.cxx | 28 ++ src/Message/Message_Attribute.hxx | 53 +++ src/Message/Message_AttributeMeter.cxx | 97 +++++ src/Message/Message_AttributeMeter.hxx | 75 ++++ src/Message/Message_AttributeObject.hxx | 44 +++ src/Message/Message_AttributeStream.cxx | 41 +++ src/Message/Message_AttributeStream.hxx | 43 +++ src/Message/Message_CompositeAlerts.cxx | 155 ++++++++ src/Message/Message_CompositeAlerts.hxx | 77 ++++ src/Message/Message_Level.cxx | 189 ++++++++++ src/Message/Message_Level.hxx | 99 ++++++ src/Message/Message_Messenger.cxx | 40 +++ src/Message/Message_Messenger.hxx | 40 ++- src/Message/Message_MetricType.hxx | 32 ++ src/Message/Message_Printer.cxx | 35 ++ src/Message/Message_Printer.hxx | 14 + src/Message/Message_PrinterToReport.cxx | 119 +++++++ src/Message/Message_PrinterToReport.hxx | 85 +++++ src/Message/Message_Report.cxx | 328 +++++++++++++---- src/Message/Message_Report.hxx | 70 +++- src/XmlDrivers/FILES | 2 + .../XmlDrivers_MessageReportStorage.cxx | 333 ++++++++++++++++++ .../XmlDrivers_MessageReportStorage.hxx | 74 ++++ 31 files changed, 2481 insertions(+), 102 deletions(-) create mode 100644 src/Message/Message_AlertExtended.cxx create mode 100644 src/Message/Message_AlertExtended.hxx create mode 100644 src/Message/Message_Attribute.cxx create mode 100644 src/Message/Message_Attribute.hxx create mode 100644 src/Message/Message_AttributeMeter.cxx create mode 100644 src/Message/Message_AttributeMeter.hxx create mode 100644 src/Message/Message_AttributeObject.hxx create mode 100644 src/Message/Message_AttributeStream.cxx create mode 100644 src/Message/Message_AttributeStream.hxx create mode 100644 src/Message/Message_CompositeAlerts.cxx create mode 100644 src/Message/Message_CompositeAlerts.hxx create mode 100644 src/Message/Message_Level.cxx create mode 100644 src/Message/Message_Level.hxx create mode 100644 src/Message/Message_MetricType.hxx create mode 100644 src/Message/Message_PrinterToReport.cxx create mode 100644 src/Message/Message_PrinterToReport.hxx create mode 100644 src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx create mode 100644 src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx diff --git a/src/DDocStd/DDocStd_ToolsCommands.cxx b/src/DDocStd/DDocStd_ToolsCommands.cxx index 9d925859c9..d31e9e0440 100644 --- a/src/DDocStd/DDocStd_ToolsCommands.cxx +++ b/src/DDocStd/DDocStd_ToolsCommands.cxx @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include +#include //======================================================================= @@ -151,7 +153,23 @@ static Standard_Integer DDocStd_DumpCommand (Draw_Interpretor& di, return 1; } +//======================================================================= +//function : DDocStd_WriteReport +//======================================================================= + +static Standard_Integer DDocStd_WriteReport(Draw_Interpretor& di,Standard_Integer n, const char** a) +{ + if (n < 2) + { + di << "DDocStd_WriteReport : Error not enough argument\n"; + return 1; + } + TCollection_ExtendedString aPath (a[1]); + MESSAGE_STORE_XML_REPORT (aPath); + + return 0; +} //======================================================================= //function : ModificationCommands @@ -174,5 +192,9 @@ void DDocStd::ToolsCommands(Draw_Interpretor& theCommands) "DumpCommand (DOC)", __FILE__, DDocStd_DumpCommand, g); + theCommands.Add ("WriteReport", + "WriteReport path", + __FILE__, DDocStd_WriteReport, g); + } diff --git a/src/Draw/Draw_BasicCommands.cxx b/src/Draw/Draw_BasicCommands.cxx index 7943efc645..8ccfa00934 100644 --- a/src/Draw/Draw_BasicCommands.cxx +++ b/src/Draw/Draw_BasicCommands.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1005,6 +1006,115 @@ static int dsetsignal (Draw_Interpretor& theDI, Standard_Integer theArgNb, const return 0; } +//============================================================================== +//function : dsetreportprinter +//purpose : +//============================================================================== +static Message_SequenceOfPrinters MyDeactivatedPrinters; + +static Standard_Integer dsetreportprinter(Draw_Interpretor&, Standard_Integer n, const char** a) +{ + if (n != 2) + { + std::cout << "Enable or disable report printer: " << a[0] << " {on|off}" << std::endl; + return 1; + } + + const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True); + const Handle(Message_Messenger)& aMessenger = Message::DefaultMessenger(); + if (! strcmp (a[1], "on") && n == 2) + { + if (aReport->IsActiveInMessenger (aMessenger)) + { + std::cout << "Error: report printer has been already activated." << std::endl; + return 1; + } + // store current printers in cache to restore them by deactivation current printer + MyDeactivatedPrinters = aMessenger->Printers(); + aMessenger->ChangePrinters().Clear(); + + aReport->ActivateInMessenger (Standard_True); + } + else if (! strcmp (a[1], "off") && n == 2) + { + if (!aReport->IsActiveInMessenger()) + { + std::cout << "Report printer was not activated." << std::endl; + return 1; + } + aReport->ActivateInMessenger (Standard_False); + + aMessenger->ChangePrinters().Assign (MyDeactivatedPrinters); + } + else + { + std::cout << "Unrecognized option(s): " << a[1] << std::endl; + return 1; + } + return 0; +} + +//============================================================================== +//function : dsetreportmetric +//purpose : +//============================================================================== +static Standard_Integer dsetreportmetric(Draw_Interpretor&, Standard_Integer n, const char** a) +{ + if (n < 1) + { + std::cout << "Report metric activation: " << a[0] << " [metric_1 metric_2 ...]" << std::endl; + return 1; + } + + const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True); + if (aReport.IsNull()) + return 1; + + aReport->ClearMetrics(); + for (int i = 1; i < n; i++) + { + Standard_Integer aMetricId = Draw::Atoi (a [i]); + if (aMetricId < Message_MetricType_UserTimeCPU || aMetricId > Message_MetricType_MemHeapUsage) + { + std::cout << "Unrecognized message metric: " << aMetricId << std::endl; + return 1; + } + aReport->SetActiveMetric ((Message_MetricType)aMetricId, Standard_True); + } + + return 0; +} + +//============================================================================== +//function : dprintreport +//purpose : +//============================================================================== +static Standard_Integer dprintreport(Draw_Interpretor& di, Standard_Integer n, const char** a) +{ + if (n < 1) + { + std::cout << "Report metric activation: " << a[0] << " [messenger]" << std::endl; + return 1; + } + + const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True); + if (aReport.IsNull()) + return 1; + + if (n > 1) // default messenger + { + aReport->SendMessages (Message::DefaultMessenger()); + } + else // stream + { + Standard_SStream aSStream; + aReport->Dump (aSStream); + di << aSStream; + } + + return 0; +} + //============================================================================== //function : dtracelevel //purpose : @@ -1133,6 +1243,12 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands) __FILE__,dperf,g); theCommands.Add("dsetsignal","dsetsignal [{asis|set|unhandled|unset}=set] [{0|1|default=$CSF_FPE}]\n -- set OSD signal handler, with FPE option if argument is given", __FILE__,dsetsignal,g); + theCommands.Add("dsetreportprinter", "manage logging of messenger into default report", + __FILE__,dsetreportprinter,g); + theCommands.Add("dsetreportmetric", "dsetreportmetric [metric...] \n Activate report metrics, deactivate all if there are no parameters.\n", + __FILE__,dsetreportmetric,g); + theCommands.Add("dprintreport", "dprintreport [messenger] \n Send report content to default messenger or stream (if parameter is absent).\n", + __FILE__,dprintreport,g); theCommands.Add("dparallel", "dparallel [-occt {0|1}] [-nbThreads Count] [-nbDefThreads Count]" diff --git a/src/Message/FILES b/src/Message/FILES index 76f6fbebe5..88cc7f75ea 100755 --- a/src/Message/FILES +++ b/src/Message/FILES @@ -1,16 +1,32 @@ Message.cxx Message.hxx +Message_Alert.cxx +Message_Alert.hxx +Message_AlertExtended.cxx +Message_AlertExtended.hxx Message_Algorithm.cxx Message_Algorithm.hxx Message_Algorithm.lxx Message_ConsoleColor.hxx +Message_Attribute.cxx +Message_Attribute.hxx +Message_AttributeMeter.cxx +Message_AttributeMeter.hxx +Message_AttributeObject.hxx +Message_AttributeStream.cxx +Message_AttributeStream.hxx +Message_CompositeAlerts.cxx +Message_CompositeAlerts.hxx Message_ExecStatus.hxx Message_Gravity.hxx Message_HArrayOfMsg.hxx +Message_Level.cxx +Message_Level.hxx Message_ListIteratorOfListOfMsg.hxx Message_ListOfMsg.hxx Message_Messenger.cxx Message_Messenger.hxx +Message_MetricType.hxx Message_Msg.cxx Message_Msg.hxx Message_Msg.lxx @@ -22,6 +38,8 @@ Message_PrinterOStream.cxx Message_PrinterOStream.hxx Message_PrinterSystemLog.cxx Message_PrinterSystemLog.hxx +Message_PrinterToReport.cxx +Message_PrinterToReport.hxx Message_ProgressIndicator.cxx Message_ProgressIndicator.hxx Message_ProgressIndicator.lxx @@ -35,8 +53,6 @@ Message_SequenceOfPrinters.hxx Message_SequenceOfProgressScale.hxx Message_Status.hxx Message_StatusType.hxx -Message_Alert.cxx -Message_Alert.hxx Message_ListOfAlert.hxx Message_Report.cxx Message_Report.hxx diff --git a/src/Message/Message.cxx b/src/Message/Message.cxx index b540ae5fb2..f15d8c51d4 100644 --- a/src/Message/Message.cxx +++ b/src/Message/Message.cxx @@ -17,18 +17,49 @@ #include #include +#include #include #include #include + +static Handle(Message_Messenger) MyMessenger; + //======================================================================= //function : DefaultMessenger //purpose : //======================================================================= -const Handle(Message_Messenger)& Message::DefaultMessenger () + +const Handle(Message_Messenger)& Message::DefaultMessenger() +{ + if (MyMessenger.IsNull()) + MyMessenger = new Message_Messenger; + return MyMessenger; +} + +//======================================================================= +//function : SetDefaultMessenger +//purpose : +//======================================================================= + +void Message::SetDefaultMessenger (const Handle(Message_Messenger)& theMessenger) +{ + MyMessenger = theMessenger; +} + +//======================================================================= +//function : DefaultReport +//purpose : +//======================================================================= + +const Handle(Message_Report)& Message::DefaultReport(const Standard_Boolean theToCreate) { - static Handle(Message_Messenger) aMessenger = new Message_Messenger; - return aMessenger; + static Handle(Message_Report) MyReport; + + if (MyReport.IsNull() && theToCreate) + MyReport = new Message_Report(); + + return MyReport; } //======================================================================= @@ -49,3 +80,82 @@ TCollection_AsciiString Message::FillTime (const Standard_Integer hour, Sprintf (t, "%.2fs", second); return TCollection_AsciiString (t); } + +namespace +{ + static Standard_CString Message_Table_PrintMetricTypeEnum[10] = + { + "NONE", "UserTimeCPU", "SystemTimeInfo", "MemPrivate", "MemVirtual", + "MemWorkingSet", "MemWorkingSetPeak", "MemSwapUsage", "MemSwapUsagePeak", "MemHeapUsage" + }; +} + +//======================================================================= +//function : MetricToString +//purpose : +//======================================================================= + +Standard_CString Message::MetricToString (const Message_MetricType theType) +{ + return Message_Table_PrintMetricTypeEnum[theType]; +} + +//======================================================================= +//function : MetricFromString +//purpose : +//======================================================================= + +Standard_Boolean Message::MetricFromString (const Standard_CString theString, + Message_MetricType& theGravity) +{ + TCollection_AsciiString aName (theString); + for (Standard_Integer aMetricIter = 0; aMetricIter <= Message_MetricType_MemHeapUsage; ++aMetricIter) + { + Standard_CString aMetricName = Message_Table_PrintMetricTypeEnum[aMetricIter]; + if (aName == aMetricName) + { + theGravity = Message_MetricType (aMetricIter); + return Standard_True; + } + } + return Standard_False; +} + +// ======================================================================= +// function : ToOSDMetric +// purpose : +// ======================================================================= +Standard_Boolean Message::ToOSDMetric (const Message_MetricType theMetric, OSD_MemInfo::Counter& theMemInfo) +{ + switch (theMetric) + { + case Message_MetricType_MemPrivate: theMemInfo = OSD_MemInfo::MemPrivate; break; + case Message_MetricType_MemVirtual: theMemInfo = OSD_MemInfo::MemVirtual; break; + case Message_MetricType_MemWorkingSet: theMemInfo = OSD_MemInfo::MemWorkingSet; break; + case Message_MetricType_MemWorkingSetPeak: theMemInfo = OSD_MemInfo::MemWorkingSetPeak; break; + case Message_MetricType_MemSwapUsage: theMemInfo = OSD_MemInfo::MemSwapUsage; break; + case Message_MetricType_MemSwapUsagePeak: theMemInfo = OSD_MemInfo::MemSwapUsagePeak; break; + case Message_MetricType_MemHeapUsage: theMemInfo = OSD_MemInfo::MemHeapUsage; break; + } + return Standard_True; +} + +// ======================================================================= +// function : ToMessageMetric +// purpose : +// ======================================================================= +Standard_Boolean Message::ToMessageMetric (const OSD_MemInfo::Counter theMemInfo, Message_MetricType& theMetric) +{ + switch (theMemInfo) + { + case OSD_MemInfo::MemPrivate: theMetric = Message_MetricType_MemPrivate; break; + case OSD_MemInfo::MemVirtual: theMetric = Message_MetricType_MemVirtual; break; + case OSD_MemInfo::MemWorkingSet: theMetric = Message_MetricType_MemWorkingSet; break; + case OSD_MemInfo::MemWorkingSetPeak: theMetric = Message_MetricType_MemWorkingSetPeak; break; + case OSD_MemInfo::MemSwapUsage: theMetric = Message_MetricType_MemSwapUsage; break; + case OSD_MemInfo::MemSwapUsagePeak: theMetric = Message_MetricType_MemSwapUsagePeak; break; + case OSD_MemInfo::MemHeapUsage: theMetric = Message_MetricType_MemHeapUsage; break; + default: return Standard_False; + } + return Standard_True; +} diff --git a/src/Message/Message.hxx b/src/Message/Message.hxx index 4be71135b3..4d728159e4 100644 --- a/src/Message/Message.hxx +++ b/src/Message/Message.hxx @@ -17,14 +17,20 @@ #ifndef _Message_HeaderFile #define _Message_HeaderFile +#include +#include +#include +#include + #include #include #include #include #include +#include + class Message_Messenger; -class TCollection_AsciiString; class Message_Msg; class Message_MsgFile; class Message_Messenger; @@ -34,6 +40,7 @@ class Message_PrinterOStream; class Message_ProgressIndicator; class Message_ProgressScale; class Message_ProgressSentry; +class Message_Report; //! Defines @@ -51,7 +58,15 @@ public: //! By default, it contains single printer directed to std::cout. //! It can be customized according to the application needs. Standard_EXPORT static const Handle(Message_Messenger)& DefaultMessenger(); - + + //! Sets default messenger. + Standard_EXPORT static void SetDefaultMessenger (const Handle(Message_Messenger)& theMessenger); + + //! returns the only one instance of Report + //! When theToCreate is true - automatically creates message report when not exist. + //! that has been created. + Standard_EXPORT static const Handle(Message_Report)& DefaultReport (const Standard_Boolean theToCreate = Standard_False); + //! Returns the string filled with values of hours, minutes and seconds. //! Example: //! 1. (5, 12, 26.3345) returns "05h:12m:26.33s", @@ -59,15 +74,45 @@ public: //! 3. (0, 0, 4.5 ) returns "4.50s" Standard_EXPORT static TCollection_AsciiString FillTime (const Standard_Integer Hour, const Standard_Integer Minute, const Standard_Real Second); - - + //! Determines the metric from the given string identifier. + //! @param theString string identifier + //! @param theType detected type of metric + //! @return TRUE if string identifier is known + Standard_EXPORT static Standard_Boolean MetricFromString (const Standard_CString theString, + Message_MetricType& theType); + + //! Returns the string name for a given metric type. + //! @param theType metric type + //! @return string identifier from the list of Message_MetricType + Standard_EXPORT static Standard_CString MetricToString (const Message_MetricType theType); + + //! Returns the metric type from the given string identifier. + //! @param theString string identifier + //! @return metric type or Message_MetricType_None if string identifier is invalid + static Message_MetricType MetricFromString (const Standard_CString theString) + { + Message_MetricType aMetric = Message_MetricType_None; + MetricFromString (theString, aMetric); + return aMetric; + } + + //! Converts message metric to OSD memory info type. + //! @param theMetric [in] message metric + //! @param theMemInfo [out] filled memory info type + //! @return true if converted + static Standard_EXPORT Standard_Boolean ToOSDMetric (const Message_MetricType theMetric, OSD_MemInfo::Counter& theMemInfo); + + //! Converts OSD memory info type to message metric. + //! @param theMemInfo [int] memory info type + //! @param theMetric [out] filled message metric + //! @return true if converted + static Standard_EXPORT Standard_Boolean ToMessageMetric (const OSD_MemInfo::Counter theMemInfo, Message_MetricType& theMetric); protected: - private: diff --git a/src/Message/Message_Alert.hxx b/src/Message/Message_Alert.hxx index 030efb0f99..a460787354 100644 --- a/src/Message/Message_Alert.hxx +++ b/src/Message/Message_Alert.hxx @@ -54,7 +54,6 @@ public: //! Base implementation always returns true. virtual Standard_EXPORT Standard_Boolean Merge (const Handle(Message_Alert)& theTarget); - // OCCT RTTI DEFINE_STANDARD_RTTIEXT(Message_Alert,Standard_Transient) }; diff --git a/src/Message/Message_AlertExtended.cxx b/src/Message/Message_AlertExtended.cxx new file mode 100644 index 0000000000..843c3b6d31 --- /dev/null +++ b/src/Message/Message_AlertExtended.cxx @@ -0,0 +1,91 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include +#include +#include +#include + +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Message_AlertExtended,Message_Alert) + +//======================================================================= +//function : GetMessageKey +//purpose : +//======================================================================= + +Standard_CString Message_AlertExtended::GetMessageKey () const +{ + if (myAttribute.IsNull()) + return Message_Alert::GetMessageKey(); + + return myAttribute->GetMessageKey(); +} + +//======================================================================= +//function : CompositeAlerts +//purpose : +//======================================================================= +Handle(Message_CompositeAlerts) Message_AlertExtended::CompositeAlerts (const Standard_Boolean theToCreate) +{ + if (myCompositAlerts.IsNull() && theToCreate) + myCompositAlerts = new Message_CompositeAlerts(); + + return myCompositAlerts; +} + +//======================================================================= +//function : SupportsMerge +//purpose : +//======================================================================= +Standard_Boolean Message_AlertExtended::SupportsMerge () const +{ + if (myCompositAlerts.IsNull()) + return Standard_True; + + // hierarchical alerts can not be merged + for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter) + { + if (!myCompositAlerts->Alerts ((Message_Gravity)aGravIter).IsEmpty()) + return Standard_False; + } + + return Standard_True; +} + +//======================================================================= +//function : Merge +//purpose : +//======================================================================= +Standard_Boolean Message_AlertExtended::Merge (const Handle(Message_Alert)& /*theTarget*/) +{ + // by default, merge trivially + return Standard_False; +} + +//======================================================================= +//function : AddAlert +//purpose : +//======================================================================= +Handle(Message_Alert) Message_AlertExtended::AddAlert (const Handle(Message_Report)& theReport, + const Handle(Message_Attribute)& theAttribute, + const Message_Gravity theGravity) +{ + Handle(Message_AlertExtended) anAlert = new Message_AlertExtended(); + anAlert->SetAttribute (theAttribute); + theReport->AddAlert (theGravity, anAlert); + + return anAlert; +} diff --git a/src/Message/Message_AlertExtended.hxx b/src/Message/Message_AlertExtended.hxx new file mode 100644 index 0000000000..8c0420836d --- /dev/null +++ b/src/Message/Message_AlertExtended.hxx @@ -0,0 +1,89 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_AlertExtended_HeaderFile +#define _Message_AlertExtended_HeaderFile + +#include +#include +#include + +class Message_Attribute; +class Message_Report; + +DEFINE_STANDARD_HANDLE(Message_AlertExtended, Message_Alert) + +class Message_CompositeAlerts; + +//! Inherited class of Message_Alert with some additional information. +//! +//! It has Message_Attributes to provide the alert name, and other custom information +//! +//! It has a container of composite alerts, if the alert might provide +//! sub-alerts collecting. +//! +class Message_AlertExtended : public Message_Alert +{ +public: + //! Empty constructor + Standard_EXPORT Message_AlertExtended() : Message_Alert() {} + + //! Return a C string to be used as a key for generating text user + //! messages describing this alert. + //! The messages are generated with help of Message_Msg class, in + //! Message_Report::Dump(). + //! Base implementation returns dynamic type name of the instance. + Standard_EXPORT virtual Standard_CString GetMessageKey () const Standard_OVERRIDE; + + //! Sets container of the alert attributes + //! @param theAttributes an attribute values + void SetAttribute (const Handle(Message_Attribute)& theAttribute) { myAttribute = theAttribute; } + + //! Returns container of the alert attributes + //! @param theAttributes an attribute values + const Handle(Message_Attribute)& Attribute() const { return myAttribute; } + + //! Returns class provided hierarchy of alerts if created or create if the parameter is true + //! @param isCreate if composite alert has not been created for this alert, it should be created + //! @return instance or NULL + Standard_EXPORT Handle(Message_CompositeAlerts) CompositeAlerts (const Standard_Boolean theToCreate = Standard_False); + + //! Return true if this type of alert can be merged with other + //! of the same type to avoid duplication. + //! Hierarchical alerts can not be merged + //! Basis implementation returns true. + virtual Standard_EXPORT Standard_Boolean SupportsMerge() const Standard_OVERRIDE; + + //! If possible, merge data contained in this alert to theTarget. + //! @return True if merged. + //! Base implementation always returns false. + virtual Standard_EXPORT Standard_Boolean Merge (const Handle(Message_Alert)& theTarget) Standard_OVERRIDE; + + //! Creates new instance of the alert and put it into report with Message_Info gravity. + //! It does nothing if such kind of gravity is not active in the report + //! @param theReport the message report where new alert is placed + //! @param theAttribute container of additional values of the alert + //! @return created alert or NULL if Message_Info is not active in report + static Standard_EXPORT Handle(Message_Alert) AddAlert (const Handle(Message_Report)& theReport, + const Handle(Message_Attribute)& theAttribute, + const Message_Gravity theGravity); + + DEFINE_STANDARD_RTTIEXT(Message_AlertExtended, Message_Alert) + +protected: + + Handle(Message_CompositeAlerts) myCompositAlerts; //!< class provided hierarchical structure of alerts + Handle(Message_Attribute) myAttribute; //!< container of the alert attributes +}; + +#endif // _Message_Alert_HeaderFile diff --git a/src/Message/Message_Attribute.cxx b/src/Message/Message_Attribute.cxx new file mode 100644 index 0000000000..6efcd0f7ba --- /dev/null +++ b/src/Message/Message_Attribute.cxx @@ -0,0 +1,28 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Message_Attribute, Standard_Transient) + +//======================================================================= +//function : GetMessageKey +//purpose : +//======================================================================= + +Standard_CString Message_Attribute::GetMessageKey () const +{ + return !myName.IsEmpty() ? myName.ToCString() : ""; +} diff --git a/src/Message/Message_Attribute.hxx b/src/Message/Message_Attribute.hxx new file mode 100644 index 0000000000..cce24fd803 --- /dev/null +++ b/src/Message/Message_Attribute.hxx @@ -0,0 +1,53 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_Attribute_HeaderFile +#define _Message_Attribute_HeaderFile + +#include +#include + +DEFINE_STANDARD_HANDLE(Message_Attribute, Standard_Transient) + +//! Additional information of extended alert attribute +//! To provide other custom attribute container, it might be redefined. +class Message_Attribute : public Standard_Transient +{ +public: + //! Empty constructor + Standard_EXPORT Message_Attribute (const TCollection_AsciiString& theName = TCollection_AsciiString()) + : myName (theName) {} + + //! Return a C string to be used as a key for generating text user + //! messages describing this alert. + //! The messages are generated with help of Message_Msg class, in + //! Message_Report::Dump(). + //! Base implementation returns dynamic type name of the instance. + virtual Standard_EXPORT Standard_CString GetMessageKey () const; + + //! Returns custom name of alert if it is set + //! @return alert name + const TCollection_AsciiString& GetName() const { return myName; } + + //! Sets the custom name of alert + //! @param theName a name for the alert + void SetName (const TCollection_AsciiString& theName) { myName = theName; } + + DEFINE_STANDARD_RTTIEXT(Message_Attribute, Standard_Transient) + +private: + TCollection_AsciiString myName; //!< alert name, if defined is used in GetMessageKey + +}; + +#endif // _Message_Attribute_HeaderFile diff --git a/src/Message/Message_AttributeMeter.cxx b/src/Message/Message_AttributeMeter.cxx new file mode 100644 index 0000000000..227c4b5e61 --- /dev/null +++ b/src/Message/Message_AttributeMeter.cxx @@ -0,0 +1,97 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeMeter, Message_Attribute) + +//======================================================================= +//function : SetValues +//purpose : +//======================================================================= +Message_AttributeMeter::Message_AttributeMeter (const TCollection_AsciiString& theName) +: Message_Attribute(theName) +{ +} + +//======================================================================= +//function : HasMetric +//purpose : +//======================================================================= +Standard_Boolean Message_AttributeMeter::HasMetric (const Message_MetricType& theMetric) const +{ + return myMetrics.IsBound (theMetric); +} + +//======================================================================= +//function : IsMetricValid +//purpose : +//======================================================================= +Standard_Boolean Message_AttributeMeter::IsMetricValid (const Message_MetricType& theMetric) const +{ + return Abs (StartValue (theMetric) - UndefinedMetricValue()) > Precision::Confusion() && + Abs (StopValue (theMetric) - UndefinedMetricValue()) > Precision::Confusion(); +} + +//======================================================================= +//function : StartValue +//purpose : +//======================================================================= +Standard_Real Message_AttributeMeter::StartValue (const Message_MetricType& theMetric) const +{ + if (!HasMetric (theMetric)) + return UndefinedMetricValue(); + + return myMetrics.Seek (theMetric)->first; +} + +//======================================================================= +//function : SetStartValue +//purpose : +//======================================================================= +void Message_AttributeMeter::SetStartValue (const Message_MetricType& theMetric, const Standard_Real theValue) +{ + if (!HasMetric (theMetric)) + { + myMetrics.Bind (theMetric, std::make_pair (theValue, UndefinedMetricValue())); + } + myMetrics.ChangeFind (theMetric).first = theValue; +} + +//======================================================================= +//function : StopValue +//purpose : +//======================================================================= +Standard_Real Message_AttributeMeter::StopValue (const Message_MetricType& theMetric) const +{ + if (!HasMetric (theMetric)) + return UndefinedMetricValue(); + + return myMetrics.Find (theMetric).second; +} + +//======================================================================= +//function : SetStopValue +//purpose : +//======================================================================= +void Message_AttributeMeter::SetStopValue (const Message_MetricType& theMetric, const Standard_Real theValue) +{ + if (!HasMetric (theMetric)) + { + // start value should be already set + return; + } + myMetrics.ChangeFind (theMetric).second = theValue; +} diff --git a/src/Message/Message_AttributeMeter.hxx b/src/Message/Message_AttributeMeter.hxx new file mode 100644 index 0000000000..f563c28377 --- /dev/null +++ b/src/Message/Message_AttributeMeter.hxx @@ -0,0 +1,75 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_AttributeMeter_HeaderFile +#define _Message_AttributeMeter_HeaderFile + +#include +#include + +#include + +class Message_Alert; + +//! Alert object storing alert metrics values. +//! Start and stop values for each metric. +class Message_AttributeMeter : public Message_Attribute +{ +public: + + //! Returns default value of the metric when it is not defined + //! @return undefined value + static Standard_Real UndefinedMetricValue() { return -1.0; } + +public: + + //! Constructor with string argument + Standard_EXPORT Message_AttributeMeter (const TCollection_AsciiString& theName = TCollection_AsciiString()); + + //! Checks whether the attribute has values for the metric + //! @param theMetric [in] metric type + //! @return true if the metric values exist in the attribute + Standard_EXPORT Standard_Boolean HasMetric (const Message_MetricType& theMetric) const; + + //! Returns true when both values of the metric are set. + //! @param theMetric [in] metric type + //! @return true if metric values are valid + Standard_EXPORT Standard_Boolean IsMetricValid (const Message_MetricType& theMetric) const; + + //! Returns start value for the metric + //! @param theMetric [in] metric type + //! @return real value + Standard_EXPORT Standard_Real StartValue (const Message_MetricType& theMetric) const; + + //! Sets start values for the metric + //! @param theMetric [in] metric type + Standard_EXPORT void SetStartValue (const Message_MetricType& theMetric, const Standard_Real theValue); + + //! Returns stop value for the metric + //! @param theMetric [in] metric type + //! @return real value + Standard_EXPORT Standard_Real StopValue (const Message_MetricType& theMetric) const; + + //! Sets stop values for the metric + //! @param theMetric [in] metric type + Standard_EXPORT void SetStopValue (const Message_MetricType& theMetric, const Standard_Real theValue); + + DEFINE_STANDARD_RTTIEXT(Message_AttributeMeter, Message_Attribute) + +private: + + typedef std::pair StartToStopValue; + NCollection_DataMap myMetrics; //!< computed metrics +}; + +#endif // _Message_AttributeMeter_HeaderFile diff --git a/src/Message/Message_AttributeObject.hxx b/src/Message/Message_AttributeObject.hxx new file mode 100644 index 0000000000..3775685da1 --- /dev/null +++ b/src/Message/Message_AttributeObject.hxx @@ -0,0 +1,44 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_AttributeObject_HeaderFile +#define _Message_AttributeObject_HeaderFile + +#include + +class Standard_Transient; + +//! Alert object storing a transient object +class Message_AttributeObject : public Message_Attribute +{ +public: + //! Constructor with string argument + Message_AttributeObject (const Handle(Standard_Transient)& theObject, + const TCollection_AsciiString& theName = TCollection_AsciiString()) + : Message_Attribute (theName) { myObject = theObject; } + + //! Returns object + //! @return the object instance + const Handle(Standard_Transient)& Object() { return myObject; } + + //! Sets the object + //! @param theObject an instance + void SetObject (const Handle(Standard_Transient)& theObject) { myObject = theObject; } + + DEFINE_STANDARD_RTTI_INLINE(Message_AttributeObject, Message_Attribute) + +private: + Handle(Standard_Transient) myObject; //!< alert object +}; + +#endif // _Message_AttributeObject_HeaderFile diff --git a/src/Message/Message_AttributeStream.cxx b/src/Message/Message_AttributeStream.cxx new file mode 100644 index 0000000000..f0cf931415 --- /dev/null +++ b/src/Message/Message_AttributeStream.cxx @@ -0,0 +1,41 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeStream, Message_Attribute) + +//======================================================================= +//function : SetValues +//purpose : +//======================================================================= +Message_AttributeStream::Message_AttributeStream (const Standard_SStream& theStream, + const TCollection_AsciiString& theName) +: Message_Attribute(theName) +{ + SetStream (theStream); +} + +//======================================================================= +//function : SetStream +//purpose : +//======================================================================= + +void Message_AttributeStream::SetStream (const Standard_SStream& theStream) +{ + myStream.str (""); + + TCollection_AsciiString aStreamStr (theStream.str().c_str()); + myStream << aStreamStr; +} + diff --git a/src/Message/Message_AttributeStream.hxx b/src/Message/Message_AttributeStream.hxx new file mode 100644 index 0000000000..c4a73527fa --- /dev/null +++ b/src/Message/Message_AttributeStream.hxx @@ -0,0 +1,43 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_AttributeStream_HeaderFile +#define _Message_AttributeStream_HeaderFile + +#include + +#include +#include + +//! Alert object storing stream values +class Message_AttributeStream : public Message_Attribute +{ +public: + + //! Constructor with string argument + Standard_EXPORT Message_AttributeStream (const Standard_SStream& theStream, + const TCollection_AsciiString& theName = TCollection_AsciiString()); + + //! Returns stream value + const Standard_SStream& Stream() const { return myStream; } + + //! Sets stream value + Standard_EXPORT void SetStream (const Standard_SStream& theStream); + + DEFINE_STANDARD_RTTIEXT(Message_AttributeStream, Message_Attribute) + +private: + Standard_SStream myStream; //!< container of values +}; + +#endif // _Message_AttributeStream_HeaderFile diff --git a/src/Message/Message_CompositeAlerts.cxx b/src/Message/Message_CompositeAlerts.cxx new file mode 100644 index 0000000000..48d0e14be9 --- /dev/null +++ b/src/Message/Message_CompositeAlerts.cxx @@ -0,0 +1,155 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Message_CompositeAlerts, Standard_Transient) + +//======================================================================= +//function : Alerts +//purpose : +//======================================================================= +const Message_ListOfAlert& Message_CompositeAlerts::Alerts (const Message_Gravity theGravity) const +{ + static const Message_ListOfAlert anEmptyList; + Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), + "Requesting alerts for gravity not in valid range", anEmptyList); + + return myAlerts[theGravity]; +} + +//======================================================================= +//function : AddAlert +//purpose : +//======================================================================= +Standard_Boolean Message_CompositeAlerts::AddAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert) +{ + Standard_ASSERT_RETURN (! theAlert.IsNull(), "Attempt to add null alert", Standard_False); + Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), + "Adding alert with gravity not in valid range", Standard_False); + + Message_ListOfAlert& aList = myAlerts[theGravity]; + if (theAlert->SupportsMerge() && ! aList.IsEmpty()) + { + // merge is performed only for alerts of exactly same type + const Handle(Standard_Type)& aType = theAlert->DynamicType(); + for (Message_ListOfAlert::Iterator anIt(aList); anIt.More(); anIt.Next()) + { + // if merged successfully, just return + if (aType == anIt.Value()->DynamicType() && theAlert->Merge (anIt.Value())) + return Standard_False; + } + } + + // if not merged, just add to the list + aList.Append (theAlert); + return Standard_True; +} + +//======================================================================= +//function : RemoveAlert +//purpose : +//======================================================================= +Standard_Boolean Message_CompositeAlerts::RemoveAlert (Message_Gravity theGravity, + const Handle(Message_Alert)& theAlert) +{ + Standard_ASSERT_RETURN (! theAlert.IsNull(), "Attempt to add null alert", Standard_False); + Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), + "Adding alert with gravity not in valid range", Standard_False); + + Message_ListOfAlert& anAlerts = myAlerts[theGravity]; + if (!anAlerts.Contains (theAlert)) + return Standard_False; + + return anAlerts.Remove (theAlert); +} + +//======================================================================= +//function : HasAlerts +//purpose : +//======================================================================= + +Standard_Boolean Message_CompositeAlerts::HasAlert (const Handle(Message_Alert)& theAlert) +{ + for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter) + { + const Message_ListOfAlert& anAlerts = Alerts ((Message_Gravity)aGravIter); + if (anAlerts.Contains (theAlert)) + return Standard_True; + } + return Standard_False; +} + +//======================================================================= +//function : HasAlerts +//purpose : +//======================================================================= +Standard_Boolean Message_CompositeAlerts::HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity) +{ + Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), + "Requesting alerts for gravity not in valid range", Standard_False); + + for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next()) + { + if (anIt.Value()->IsInstance(theType)) + return Standard_True; + } + return Standard_False; +} + +//======================================================================= +//function : Clear +//purpose : +//======================================================================= +void Message_CompositeAlerts::Clear () +{ + for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i) + { + myAlerts[i].Clear(); + } +} + +//======================================================================= +//function : Clear +//purpose : +//======================================================================= +void Message_CompositeAlerts::Clear (Message_Gravity theGravity) +{ + Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), + "Requesting alerts for gravity not in valid range", ); + myAlerts[theGravity].Clear(); +} + +//======================================================================= +//function : Clear +//purpose : +//======================================================================= +void Message_CompositeAlerts::Clear (const Handle(Standard_Type)& theType) +{ + for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i) + { + for (Message_ListOfAlert::Iterator anIt (myAlerts[i]); anIt.More(); ) + { + if (anIt.Value().IsNull() || anIt.Value()->IsInstance (theType)) + { + myAlerts[i].Remove (anIt); + } + else + { + anIt.More(); + } + } + } +} diff --git a/src/Message/Message_CompositeAlerts.hxx b/src/Message/Message_CompositeAlerts.hxx new file mode 100644 index 0000000000..0864e05b6f --- /dev/null +++ b/src/Message/Message_CompositeAlerts.hxx @@ -0,0 +1,77 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_CompositeAlerts_HeaderFile +#define _Message_CompositeAlerts_HeaderFile + +#include +#include +#include +#include + +class Message_CompositeAlerts; +DEFINE_STANDARD_HANDLE(Message_CompositeAlerts, Standard_Transient) + +//! Class providing container of alerts +class Message_CompositeAlerts : public Standard_Transient +{ +public: + //! Empty constructor + Standard_EXPORT Message_CompositeAlerts() {} + + //! Returns list of collected alerts with specified gravity + Standard_EXPORT const Message_ListOfAlert& Alerts (const Message_Gravity theGravity) const; + + //! Add alert with specified gravity. If the alert supports merge it will be merged. + //! @param theGravity an alert gravity + //! @param theAlert an alert to be added as a child alert + //! @return true if the alert is added or merged + Standard_EXPORT Standard_Boolean AddAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert); + + //! Removes alert with specified gravity. + //! @param theGravity an alert gravity + //! @param theAlert an alert to be removed from the children + //! @return true if the alert is removed + Standard_EXPORT Standard_Boolean RemoveAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert); + + //! Returns true if the alert belong the list of the child alerts. + //! @param theAlert an alert to be checked as a child alert + //! @return true if the alert is found in a container of children + Standard_EXPORT Standard_Boolean HasAlert (const Handle(Message_Alert)& theAlert); + + //! Returns true if specific type of alert is recorded with specified gravity + //! @param theType an alert type + //! @param theGravity an alert gravity + //! @return true if the alert is found in a container of children + Standard_EXPORT Standard_Boolean HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity); + + //! Clears all collected alerts + Standard_EXPORT void Clear (); + + //! Clears collected alerts with specified gravity + //! @param theGravity an alert gravity + Standard_EXPORT void Clear (Message_Gravity theGravity); + + //! Clears collected alerts with specified type + //! @param theType an alert type + Standard_EXPORT void Clear (const Handle(Standard_Type)& theType); + + DEFINE_STANDARD_RTTIEXT(Message_CompositeAlerts,Standard_Transient) + +protected: + // store messages in a lists sorted by gravity; + // here we rely on knowledge that Message_Fail is the last element of the enum + Message_ListOfAlert myAlerts[Message_Fail + 1]; //!< container of child alert for each type of gravity +}; + +#endif // _Message_CompositeAlerts_HeaderFile diff --git a/src/Message/Message_Level.cxx b/src/Message/Message_Level.cxx new file mode 100644 index 0000000000..e022264fc9 --- /dev/null +++ b/src/Message/Message_Level.cxx @@ -0,0 +1,189 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +//======================================================================= +//function : Message_Level +//purpose : +//======================================================================= +Message_Level::Message_Level() +{ + const Handle(Message_Report)& aDefaultReport = Message::DefaultReport(); + if (!aDefaultReport.IsNull() && aDefaultReport->IsActiveInMessenger()) + aDefaultReport->AddLevel (this); +} + +//======================================================================= +//function : Destructor +//purpose : +//======================================================================= +Message_Level::~Message_Level() +{ + Remove(); +} + +//======================================================================= +//function : SetRootAlert +//purpose : +//======================================================================= +void Message_Level::SetRootAlert (const Handle(Message_AlertExtended)& theAlert) +{ + myRootAlert = theAlert; + startAlert (myRootAlert); +} + +//======================================================================= +//function : AddAlert +//purpose : +//======================================================================= +Standard_Boolean Message_Level::AddAlert (const Message_Gravity theGravity, + const Handle(Message_Alert)& theAlert) +{ + Handle(Message_AlertExtended) anAlertExtended = Handle(Message_AlertExtended)::DownCast (theAlert); + if (anAlertExtended.IsNull()) + return Standard_False; + + if (myRootAlert.IsNull()) + return Standard_False; + + // looking for the parent of the parameter alert to release the previous alert + Handle(Message_AlertExtended) aRootAlert = myRootAlert; + Handle(Message_CompositeAlerts) aCompositeAlert = aRootAlert->CompositeAlerts (Standard_True); + + // update metrics of the previous alert + stopAlert (myLastAlert); + + myLastAlert = anAlertExtended; + + // set start metrics of the new alert + startAlert (myLastAlert); + + // add child alert + aCompositeAlert->AddAlert (theGravity, theAlert); + + return Standard_True; +} + +//======================================================================= +//function : AddLevelAlert +//purpose : +//======================================================================= +Standard_Boolean Message_Level::AddLevelAlert (const Message_Gravity theGravity, + const Handle(Message_Alert)& theAlert) +{ + Handle(Message_AlertExtended) aRootAlert = !myLastAlert.IsNull() ? myLastAlert : myRootAlert; + if (aRootAlert.IsNull()) + return Standard_False; + + Handle(Message_CompositeAlerts) aCompositeAlert = aRootAlert->CompositeAlerts (Standard_True); + // add child alert + aCompositeAlert->AddAlert (theGravity, theAlert); + + return Standard_True; +} + +//======================================================================= +//function : Remove() +//purpose : +//======================================================================= +void Message_Level::Remove() +{ + const Handle(Message_Report)& aDefaultReport = Message::DefaultReport(); + if (aDefaultReport.IsNull() || !aDefaultReport->IsActiveInMessenger()) + return; + + stopAlert (myLastAlert); + stopAlert (myRootAlert); + + if (!Message::DefaultReport().IsNull()) + Message::DefaultReport()->RemoveLevel (this); +} + +//======================================================================= +//function : setAlertMetrics +//purpose : +//======================================================================= +void Message_Level::setAlertMetrics (const Handle(Message_AlertExtended)& theAlert, + const Standard_Boolean theStartValue) +{ + if (theAlert.IsNull()) + return; + + Handle(Message_AttributeMeter) aMeterAttribute = Handle(Message_AttributeMeter)::DownCast (theAlert->Attribute()); + if (aMeterAttribute.IsNull()) + return; + + Handle(Message_Report) aReport = Message::DefaultReport (Standard_True); + const NCollection_Map& anActiveMetrics = aReport->ActiveMetrics(); + + // time metrics + if (anActiveMetrics.Contains (Message_MetricType_UserTimeCPU) || + anActiveMetrics.Contains (Message_MetricType_SystemTimeInfo)) + { + Standard_Real aUserSeconds, aSystemSeconds; + OSD_Chronometer::GetThreadCPU (aUserSeconds, aSystemSeconds); + + if (anActiveMetrics.Contains (Message_MetricType_UserTimeCPU)) + { + if (theStartValue) + aMeterAttribute->SetStartValue (Message_MetricType_UserTimeCPU, aUserSeconds); + else + aMeterAttribute->SetStopValue (Message_MetricType_UserTimeCPU, aUserSeconds); + } + if (anActiveMetrics.Contains (Message_MetricType_SystemTimeInfo)) + { + if (theStartValue) + aMeterAttribute->SetStartValue (Message_MetricType_SystemTimeInfo, aSystemSeconds); + else + aMeterAttribute->SetStopValue (Message_MetricType_SystemTimeInfo, aSystemSeconds); + } + } + // memory metrics + NCollection_Map aCounters; + for (NCollection_Map::Iterator anIterator (anActiveMetrics); anIterator.More(); anIterator.Next()) + { + OSD_MemInfo::Counter aMemInfo; + if (!Message::ToOSDMetric (anIterator.Value(), aMemInfo)) + continue; + + aCounters.Add (aMemInfo); + } + if (aCounters.IsEmpty()) + return; + + OSD_MemInfo aMemInfo (Standard_False); + //aMemInfo.SetActiveCounters (aCounters); + aMemInfo.Update (); + Message_MetricType aMetricType; + for (NCollection_Map::Iterator anIterator (aCounters); anIterator.More(); anIterator.Next()) + { + if (!Message::ToMessageMetric (anIterator.Value(), aMetricType)) + continue; + + if (theStartValue) + aMeterAttribute->SetStartValue (aMetricType, (Standard_Real)aMemInfo.ValuePreciseMiB (anIterator.Value())); + else + aMeterAttribute->SetStopValue (aMetricType, (Standard_Real)aMemInfo.ValuePreciseMiB (anIterator.Value())); + } +} diff --git a/src/Message/Message_Level.hxx b/src/Message/Message_Level.hxx new file mode 100644 index 0000000000..0433722811 --- /dev/null +++ b/src/Message/Message_Level.hxx @@ -0,0 +1,99 @@ +// Copyright (c) 2019 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_Level_HeaderFile +#define _Message_Level_HeaderFile + +#include +#include +#include + +#include +#include + +//! This class is an instance of Sentry to create a level in a message report +//! Constructor of the class add new (active) level in the report, destructor removes it +//! While the level is active in the report, new alerts are added below the level root alert. +//! +//! The first added alert is a root alert, other are added below the root alert +//! +//! If alert has Message_AttributeMeter attribute, active metrics of the default report are stored in +//! the attriute: start value of metric on adding alert, stop on adding another alert or closing (delete) the level +//! in the report. +//! +//! Processing of this class is implemented in Message_Report, it is used only insided it. +//! Levels using should be only through using MESSAGE_ADD_LEVEL_SENTRY only. No other code is required outside. +class Message_Level +{ + +public: + //! Constructor. Append + //! One string key is used for all alert meters. The perf meter is not started automatically, it will be done in + //! AddAlert method + Standard_EXPORT Message_Level(); + + //! Assures stopping upon destruction + Standard_EXPORT ~Message_Level(); + + //! Returns root alert of the level + //! @return alert instance or NULL + const Handle(Message_AlertExtended)& RootAlert() const { return myRootAlert; } + + //! Sets the root alert. Starts collects alert metrics if active. + //! @param theAlert an alert + Standard_EXPORT void SetRootAlert (const Handle(Message_AlertExtended)& theAlert); + + //! Adds new alert on the level. Stops the last alert metric, appends the alert and starts the alert metrics collecting. + //! Sets root alert beforehead this method using, if the root is NULL, it does nothing. + //! @param theGravity an alert gravity + //! @param theAlert an alert + //! @return true if alert is added + Standard_EXPORT Standard_Boolean AddAlert (const Message_Gravity theGravity, + const Handle(Message_Alert)& theAlert); + + //! Add new alert as a child of the last alert if exists or as a child of the root alert. + //! @param theGravity an alert gravity + //! @param theAlert an alert + //! @return true if alert is added + Standard_EXPORT Standard_Boolean AddLevelAlert (const Message_Gravity theGravity, + const Handle(Message_Alert)& theAlert); + + //! Remove the current level from the report. It stops metric collecting for the last and the root alerts. + Standard_EXPORT void Remove(); + +protected: + //! Sets start values of default report metrics into the alert + //! @param theAlert an alert + void startAlert (const Handle(Message_AlertExtended)& theAlert) { setAlertMetrics (theAlert, Standard_True); } + + //! Sets stop values of default report metrics into the alert + //! @param theAlert an alert + void stopAlert (const Handle(Message_AlertExtended)& theAlert) { setAlertMetrics (theAlert, Standard_True); } + + //! Sets current values of default report metrics into the alert. + //! Processed oly alert with Message_AttributeMeter attribute + //! @param theAlert an alert + //! @param theStartValue flag, if true, the start value is collected otherwise stop + Standard_EXPORT void setAlertMetrics (const Handle(Message_AlertExtended)& theAlert, + const Standard_Boolean theStartValue); + +protected: + Handle(Message_AlertExtended) myRootAlert; //!< root alert + Handle(Message_AlertExtended) myLastAlert; //!< last added alert on the root alert +}; + +//! @def MESSAGE_NEW_LEVEL +//! Creates a new level instance of Sentry. This row should be inserted before messages using in the method. +#define MESSAGE_ADD_LEVEL_SENTRY Message_Level aLevel; + +#endif // _Message_Level_HeaderFile diff --git a/src/Message/Message_Messenger.cxx b/src/Message/Message_Messenger.cxx index 1e44c8b220..c2e2c71799 100644 --- a/src/Message/Message_Messenger.cxx +++ b/src/Message/Message_Messenger.cxx @@ -25,6 +25,7 @@ IMPLEMENT_STANDARD_RTTIEXT(Message_Messenger,Standard_Transient) //purpose : //======================================================================= Message_Messenger::Message_Messenger () +: myOutputGravity (Message_Info) { AddPrinter ( new Message_PrinterOStream ); } @@ -35,6 +36,7 @@ Message_Messenger::Message_Messenger () //======================================================================= Message_Messenger::Message_Messenger (const Handle(Message_Printer)& thePrinter) +: myOutputGravity (Message_Info) { AddPrinter (thePrinter); } @@ -161,3 +163,41 @@ void Message_Messenger::Send (const TCollection_ExtendedString& theString, } } } + +//======================================================================= +//function : Send +//purpose : +//======================================================================= + +void Message_Messenger::Send (const Standard_SStream& theStream, + const Message_Gravity theGravity, + const Standard_Boolean putEndl) const +{ + for (Message_SequenceOfPrinters::Iterator aPrinterIter (myPrinters); aPrinterIter.More(); aPrinterIter.Next()) + { + const Handle(Message_Printer)& aPrinter = aPrinterIter.Value(); + if (!aPrinter.IsNull()) + { + aPrinter->Send (theStream, theGravity, putEndl); + } + } +} + +//======================================================================= +//function : Send +//purpose : +//======================================================================= + +void Message_Messenger::Send (const Handle(Standard_Transient)& theObject, + const Message_Gravity theGravity, + const Standard_Boolean putEndl) const +{ + for (Message_SequenceOfPrinters::Iterator aPrinterIter (myPrinters); aPrinterIter.More(); aPrinterIter.Next()) + { + const Handle(Message_Printer)& aPrinter = aPrinterIter.Value(); + if (!aPrinter.IsNull()) + { + aPrinter->Send (theObject, theGravity, putEndl); + } + } +} diff --git a/src/Message/Message_Messenger.hxx b/src/Message/Message_Messenger.hxx index 675fba3436..398c92792f 100644 --- a/src/Message/Message_Messenger.hxx +++ b/src/Message/Message_Messenger.hxx @@ -84,6 +84,12 @@ public: //! The sequence can be modified. Message_SequenceOfPrinters& ChangePrinters() { return myPrinters; } + //! Returns the output gavity used in operator << + Message_Gravity OuputGravity() const { return myOutputGravity; } + + //! Sets the output gavity used in operator << + void SetOuputGravity (const Message_Gravity theValue) { myOutputGravity = theValue; } + //! Dispatch a message to all the printers in the list. //! Three versions of string representations are accepted for //! convenience, by default all are converted to ExtendedString. @@ -98,17 +104,23 @@ public: //! See above Standard_EXPORT void Send (const TCollection_ExtendedString& theString, const Message_Gravity theGravity = Message_Warning, const Standard_Boolean putEndl = Standard_True) const; + //! See above + Standard_EXPORT void Send (const Standard_SStream& theStream, const Message_Gravity theGravity = Message_Warning, const Standard_Boolean putEndl = Standard_True) const; + + //! See above + Standard_EXPORT void Send (const Handle(Standard_Transient)& theObject, const Message_Gravity theGravity = Message_Warning, const Standard_Boolean putEndl = Standard_True) const; + private: Message_SequenceOfPrinters myPrinters; - + Message_Gravity myOutputGravity; //!< gravity used in operator << }; // CString inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, const Standard_CString theStr) { - theMessenger->Send (theStr, Message_Info, Standard_False); + theMessenger->Send (theStr, theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -116,7 +128,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, const TCollection_AsciiString& theStr) { - theMessenger->Send (theStr, Message_Info, Standard_False); + theMessenger->Send (theStr, theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -124,7 +136,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, const Handle(TCollection_HAsciiString)& theStr) { - theMessenger->Send (theStr->String(), Message_Info, Standard_False); + theMessenger->Send (theStr->String(), theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -132,7 +144,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, const TCollection_ExtendedString& theStr) { - theMessenger->Send (theStr, Message_Info, Standard_False); + theMessenger->Send (theStr, theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -140,7 +152,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, const Handle(TCollection_HExtendedString)& theStr) { - theMessenger->Send (theStr->String(), Message_Info, Standard_False); + theMessenger->Send (theStr->String(), theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -149,7 +161,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng const Standard_Integer theVal) { TCollection_AsciiString aStr (theVal); - theMessenger->Send (aStr, Message_Info, Standard_False); + theMessenger->Send (aStr, theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -158,7 +170,7 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng const Standard_Real theVal) { TCollection_AsciiString aStr (theVal); - theMessenger->Send (aStr, Message_Info, Standard_False); + theMessenger->Send (aStr, theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -166,7 +178,15 @@ inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messeng inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, const Standard_SStream& theStream) { - theMessenger->Send (theStream.str().c_str(), Message_Info, Standard_False); + theMessenger->Send (theStream, theMessenger->OuputGravity(), Standard_False); + return theMessenger; +} + +// AsciiString +inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger, + const Handle(Standard_Transient)& theObject) +{ + theMessenger->Send (theObject, theMessenger->OuputGravity(), Standard_False); return theMessenger; } @@ -181,7 +201,7 @@ inline const Handle(Message_Messenger)& // Message_EndLine inline const Handle(Message_Messenger)& Message_EndLine (const Handle(Message_Messenger)& theMessenger) { - theMessenger->Send ("", Message_Info, Standard_True); + theMessenger->Send ("", theMessenger->OuputGravity(), Standard_True); return theMessenger; } diff --git a/src/Message/Message_MetricType.hxx b/src/Message/Message_MetricType.hxx new file mode 100644 index 0000000000..a99db83399 --- /dev/null +++ b/src/Message/Message_MetricType.hxx @@ -0,0 +1,32 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_MetricType_HeaderFile +#define _Message_MetricType_HeaderFile + +//! Specifies kind of report information to collect +enum Message_MetricType +{ + Message_MetricType_None, //!< no computation + Message_MetricType_UserTimeCPU, //!< the current CPU user time in seconds + Message_MetricType_SystemTimeInfo, //!< the current CPU system time in seconds + Message_MetricType_MemPrivate, //!< OSD_MemInfo::MemPrivate + Message_MetricType_MemVirtual, //!< OSD_MemInfo::MemVirtual + Message_MetricType_MemWorkingSet, //!< OSD_MemInfo::MemWorkingSet + Message_MetricType_MemWorkingSetPeak, //!< OSD_MemInfo::MemWorkingSetPeak + Message_MetricType_MemSwapUsage, //!< OSD_MemInfo::MemSwapUsage + Message_MetricType_MemSwapUsagePeak, //!< OSD_MemInfo::MemSwapUsagePeak + Message_MetricType_MemHeapUsage //!< OSD_MemInfo::MemHeapUsage +}; + +#endif // _Message_MetricType_HeaderFile diff --git a/src/Message/Message_Printer.cxx b/src/Message/Message_Printer.cxx index 8ed2b87e6a..cc1c09878d 100644 --- a/src/Message/Message_Printer.cxx +++ b/src/Message/Message_Printer.cxx @@ -15,6 +15,7 @@ #include +#include #include #include @@ -58,3 +59,37 @@ void Message_Printer::Send (const TCollection_AsciiString& theString, Send (TCollection_ExtendedString (theString), theGravity, theToOutEol); } } + +//======================================================================= +//function : Send +//purpose : +//======================================================================= + +void Message_Printer::Send (const Standard_SStream& theStream, + const Message_Gravity theGravity, + const Standard_Boolean theToOutEol) const +{ + if (theGravity >= myTraceLevel) + { + Send (TCollection_ExtendedString (theStream.str().c_str()), theGravity, theToOutEol); + } +} + +//======================================================================= +//function : Send +//purpose : +//======================================================================= +void Message_Printer::Send (const Handle(Standard_Transient)& theObject, + const Message_Gravity theGravity, + const Standard_Boolean theToOutEol) const +{ + if (theObject.IsNull()) + return; + + if (theGravity >= myTraceLevel) + { + TCollection_ExtendedString aString = TCollection_ExtendedString (theObject->DynamicType()->Name()) + + ": " + Standard_Dump::GetPointerInfo (theObject); + Send (aString, theGravity, theToOutEol); + } +} diff --git a/src/Message/Message_Printer.hxx b/src/Message/Message_Printer.hxx index e7e70ddfbd..ae877c7081 100644 --- a/src/Message/Message_Printer.hxx +++ b/src/Message/Message_Printer.hxx @@ -23,6 +23,8 @@ #include #include #include +#include + class TCollection_ExtendedString; class TCollection_AsciiString; @@ -62,6 +64,18 @@ public: //! Default implementation calls first method Send(). Standard_EXPORT virtual void Send (const TCollection_AsciiString& theString, const Message_Gravity theGravity, const Standard_Boolean theToPutEol) const; + //! Send a string message with specified trace level. + //! Stream is converted to string value. + //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message. + //! Default implementation calls first method Send(). + Standard_EXPORT virtual void Send (const Standard_SStream& theStream, const Message_Gravity theGravity, const Standard_Boolean theToPutEol) const; + + //! Send a string message with specified trace level. + //! The object is converted to string in format: : . + //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message. + //! Default implementation calls first method Send(). + Standard_EXPORT virtual void Send (const Handle(Standard_Transient)& theObject, const Message_Gravity theGravity, const Standard_Boolean theToPutEol) const; + protected: //! Empty constructor with Message_Info trace level diff --git a/src/Message/Message_PrinterToReport.cxx b/src/Message/Message_PrinterToReport.cxx new file mode 100644 index 0000000000..a36885f07a --- /dev/null +++ b/src/Message/Message_PrinterToReport.cxx @@ -0,0 +1,119 @@ +// Created on: 2001-01-06 +// Created by: OCC Team +// Copyright (c) 2001-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Message_PrinterToReport, Message_Printer) + +//======================================================================= +//function : Report +//purpose : +//======================================================================= +const Handle(Message_Report)& Message_PrinterToReport::Report() const +{ + if (!myReport.IsNull()) + return myReport; + + return Message::DefaultReport (Standard_True); +} + +//======================================================================= +//function : Send +//purpose : +//======================================================================= +void Message_PrinterToReport::Send (const TCollection_ExtendedString& theString, + const Message_Gravity theGravity, + const Standard_Boolean putEndl) const +{ + TCollection_AsciiString aString (theString/*, myUseUtf8 ? Standard_Character(0) : '?'*/); + + if (putEndl) + { + if (myValue.IsEmpty()) + return; + + const Handle(Message_Report)& aReport = Report(); + if (!aReport->ActiveMetrics().IsEmpty()) + { + sendMetricAlert (myValue, theGravity); + return; + } + Message_AlertExtended::AddAlert (aReport, new Message_Attribute (myValue), theGravity); + ((Message_PrinterToReport*)this)->Clear(); + return; + } + ((Message_PrinterToReport*)this)->myValue += aString; +} + +//======================================================================= +//function : Send +//purpose : +//======================================================================= +void Message_PrinterToReport::Send (const Standard_SStream& theStream, + const Message_Gravity theGravity, + const Standard_Boolean /*putEndl*/) const +{ + const Handle(Message_Report)& aReport = Report(); + if (!aReport->ActiveMetrics().IsEmpty()) + { + sendMetricAlert (myValue, theGravity); + return; + } + Message_AlertExtended::AddAlert (aReport, new Message_AttributeStream (theStream, myValue), theGravity); + ((Message_PrinterToReport*)this)->Clear(); + + return; +} + +//======================================================================= +//function : Send +//purpose : +//======================================================================= +void Message_PrinterToReport::Send (const Handle(Standard_Transient)& theObject, + const Message_Gravity theGravity, + const Standard_Boolean /*putEndl*/) const +{ + const Handle(Message_Report)& aReport = Report(); + if (!aReport->ActiveMetrics().IsEmpty()) + { + sendMetricAlert (myValue, theGravity); + return; + } + + Message_AlertExtended::AddAlert (aReport, new Message_AttributeObject (theObject, myValue), theGravity); + ((Message_PrinterToReport*)this)->Clear(); +} + +//======================================================================= +//function : sendMetricAlert +//purpose : +//======================================================================= +void Message_PrinterToReport::sendMetricAlert (const TCollection_AsciiString theValue, + const Message_Gravity theGravity) const +{ + Message_AlertExtended::AddAlert (Report(), new Message_AttributeMeter (theValue), theGravity); + ((Message_PrinterToReport*)this)->Clear(); +} diff --git a/src/Message/Message_PrinterToReport.hxx b/src/Message/Message_PrinterToReport.hxx new file mode 100644 index 0000000000..8de68321e5 --- /dev/null +++ b/src/Message/Message_PrinterToReport.hxx @@ -0,0 +1,85 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Message_PrinterToReport_HeaderFile +#define _Message_PrinterToReport_HeaderFile + +#include +#include +#include +#include + +class Message_Report; + +class Message_PrinterToReport; +DEFINE_STANDARD_HANDLE(Message_PrinterToReport, Message_Printer) + +//! Implementation of a message printer associated with Message_Report +//! Send will create a new alert of the report. If string is sent, an alert is created by Eol only. +//! The alerts are sent into set report or default report of Message. +class Message_PrinterToReport : public Message_Printer +{ + DEFINE_STANDARD_RTTIEXT(Message_PrinterToReport, Message_Printer) + +public: + //! Create printer for redirecting messages into report. + Message_PrinterToReport() {} + + ~Message_PrinterToReport() {} + + //! Returns the current or default report + Standard_EXPORT const Handle(Message_Report)& Report() const; + + //! Sets the printer report + //! @param theReport report for messages processing, if NULL, the default report is used + Standard_EXPORT void SetReport (const Handle(Message_Report)& theReport) { myReport = theReport; } + + //!< Returns the first sent value + const TCollection_AsciiString& Value() { return myValue; } + + //! Clears current values + Standard_EXPORT void Clear() { myValue.Clear(); } + + //! Appends a new alert into message report if Endl is false or send a new extended alert with attribute on value + //! Use Message_EndLine to finalize the current alert + Standard_EXPORT virtual void Send (const TCollection_ExtendedString& theString, + const Message_Gravity theGravity, + const Standard_Boolean putEndl = Standard_True) const Standard_OVERRIDE; + + //! Send a string message with specified trace level. + //! Stream is converted to string value. + //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message. + //! Default implementation calls first method Send(). + Standard_EXPORT virtual void Send (const Standard_SStream& theStream, + const Message_Gravity theGravity, + const Standard_Boolean theToPutEol) const Standard_OVERRIDE; + + //! Send a string message with specified trace level. + //! The object is converted to string in format: : . + //! The parameter theToPutEol specified whether end-of-line should be added to the end of the message. + //! Default implementation calls first method Send(). + Standard_EXPORT virtual void Send (const Handle(Standard_Transient)& theObject, + const Message_Gravity theGravity, + const Standard_Boolean theToPutEol) const Standard_OVERRIDE; +protected: + + //! Send an alert with metrics active in the current report + Standard_EXPORT void sendMetricAlert (const TCollection_AsciiString theValue, + const Message_Gravity theGravity) const; + +private: + Handle(Message_Report) myReport; //!< the report for sending alerts + TCollection_AsciiString myValue; //!< the union of sent strings until Eol +}; + +#endif // _Message_PrinterToReport_HeaderFile diff --git a/src/Message/Message_Report.cxx b/src/Message/Message_Report.cxx index 07324599d2..74e1eff6e4 100644 --- a/src/Message/Message_Report.cxx +++ b/src/Message/Message_Report.cxx @@ -14,9 +14,17 @@ // commercial license or contractual agreement. #include + +#include +#include +#include #include #include +#include + #include +#include +#include IMPLEMENT_STANDARD_RTTIEXT(Message_Report,Standard_Transient) @@ -26,6 +34,7 @@ IMPLEMENT_STANDARD_RTTIEXT(Message_Report,Standard_Transient) //======================================================================= Message_Report::Message_Report () +: myLimit (-1) { } @@ -36,28 +45,50 @@ Message_Report::Message_Report () void Message_Report::AddAlert (Message_Gravity theGravity, const Handle(Message_Alert)& theAlert) { - Standard_ASSERT_RETURN (! theAlert.IsNull(), "Attempt to add null alert",); - Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), - "Adding alert with gravity not in valid range",); - Standard_Mutex::Sentry aSentry (myMutex); - // iterate by already recorded alerts and try to merge new one with one of those - Message_ListOfAlert &aList = myAlerts[theGravity]; - if (theAlert->SupportsMerge() && ! aList.IsEmpty()) + // alerts of the top level + if (myAlertLevels.IsEmpty()) { - // merge is performed only for alerts of exactly same type - const Handle(Standard_Type)& aType = theAlert->DynamicType(); - for (Message_ListOfAlert::Iterator anIt(aList); anIt.More(); anIt.Next()) + Handle (Message_CompositeAlerts) aCompositeAlert = compositeAlerts (Standard_True); + if (aCompositeAlert->AddAlert (theGravity, theAlert)) + return; + + // remove alerts under the report only + const Message_ListOfAlert& anAlerts = aCompositeAlert->Alerts (theGravity); + if (anAlerts.Extent() > myLimit) { - // if merged successfully, just return - if (aType == anIt.Value()->DynamicType() && theAlert->Merge (anIt.Value())) - return; + aCompositeAlert->RemoveAlert (theGravity, anAlerts.First()); } + return; } - // if not merged, just add to the list - aList.Append (theAlert); + // if there are some levels of alerts + // iterate by already recorded alerts and try to merge new one with one of those + Message_Level* aLevel = myAlertLevels.Last(); + + // level has root alert, the new alert will be placed below the root + if (!aLevel->RootAlert().IsNull()) + { + aLevel->AddAlert (theGravity, theAlert); + return; + } + + Handle(Message_AlertExtended) anAlert = Handle(Message_AlertExtended)::DownCast (theAlert); + if (anAlert.IsNull()) + return; + // place new alert as a root of the level, after place the level alert below the report or + // below the previous level + aLevel->SetRootAlert (anAlert); + + if (myAlertLevels.Size() == 1) // this is the first level, so root alert should be pushed in the report composite of alerts + compositeAlerts (Standard_True)->AddAlert (theGravity, theAlert); + else + { + // root alert of next levels should be pushed under the previous level + Message_Level* aPrevLevel = myAlertLevels.Value (myAlertLevels.Size() - 1); // previous level + aPrevLevel->AddLevelAlert (theGravity, theAlert); + } } //======================================================================= @@ -68,9 +99,10 @@ void Message_Report::AddAlert (Message_Gravity theGravity, const Handle(Message_ const Message_ListOfAlert& Message_Report::GetAlerts (Message_Gravity theGravity) const { static const Message_ListOfAlert anEmptyList; - Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), - "Requesting alerts for gravity not in valid range", anEmptyList); - return myAlerts[theGravity]; + if (myCompositAlerts.IsNull()) + return anEmptyList; + + return myCompositAlerts->Alerts (theGravity); } //======================================================================= @@ -80,9 +112,9 @@ const Message_ListOfAlert& Message_Report::GetAlerts (Message_Gravity theGravity Standard_Boolean Message_Report::HasAlert (const Handle(Standard_Type)& theType) { - for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity) + for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter) { - if (HasAlert (theType, (Message_Gravity)iGravity)) + if (HasAlert (theType, (Message_Gravity)aGravIter)) return Standard_True; } return Standard_False; @@ -95,27 +127,103 @@ Standard_Boolean Message_Report::HasAlert (const Handle(Standard_Type)& theType) Standard_Boolean Message_Report::HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity) { - Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), - "Requesting alerts for gravity not in valid range", Standard_False); - for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next()) + if (compositeAlerts().IsNull()) + return Standard_False; + + return compositeAlerts()->HasAlert (theType, theGravity); +} + +//======================================================================= +//function : IsActiveInMessenger +//purpose : +//======================================================================= + +Standard_Boolean Message_Report::IsActiveInMessenger (const Handle(Message_Messenger)& theMessenger) const +{ + Handle(Message_Messenger) aMessenger = theMessenger.IsNull() ? Message::DefaultMessenger() : theMessenger; + for (Message_SequenceOfPrinters::Iterator anIterator (aMessenger->Printers()); anIterator.More(); anIterator.Next()) { - if (anIt.Value()->IsInstance(theType)) + if (anIterator.Value()->IsKind(STANDARD_TYPE (Message_PrinterToReport)) && + Handle(Message_PrinterToReport)::DownCast (anIterator.Value())->Report() == this) return Standard_True; } return Standard_False; } //======================================================================= -//function : Clear +//function : ActivateInMessenger //purpose : //======================================================================= -void Message_Report::Clear () +void Message_Report::ActivateInMessenger (const Standard_Boolean toActivate, + const Handle(Message_Messenger)& theMessenger) const { - for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i) + if (toActivate == IsActiveInMessenger()) + return; + + Handle(Message_Messenger) aMessenger = theMessenger.IsNull() ? Message::DefaultMessenger() : theMessenger; + if (toActivate) { - myAlerts[i].Clear(); + Handle (Message_PrinterToReport) aPrinterToReport = new Message_PrinterToReport(); + aPrinterToReport->SetReport (this); + aMessenger->AddPrinter (aPrinterToReport); } + else // deactivate + { + Message_SequenceOfPrinters aPrintersToRemove; + for (Message_SequenceOfPrinters::Iterator anIterator (aMessenger->Printers()); anIterator.More(); anIterator.Next()) + { + const Handle(Message_Printer) aPrinter = anIterator.Value(); + if (aPrinter->IsKind(STANDARD_TYPE (Message_PrinterToReport)) && + Handle(Message_PrinterToReport)::DownCast (aPrinter)->Report() == this) + aPrintersToRemove.Append (aPrinter); + } + for (Message_SequenceOfPrinters::Iterator anIterator (aPrintersToRemove); anIterator.More(); anIterator.Next()) + { + aMessenger->RemovePrinter (anIterator.Value()); + } + } +} + +//======================================================================= +//function : AddLevel +//purpose : +//======================================================================= + +void Message_Report::AddLevel (Message_Level* theLevel) +{ + myAlertLevels.Append (theLevel); +} + +//======================================================================= +//function : RemoveLevel +//purpose : +//======================================================================= + +void Message_Report::RemoveLevel (Message_Level* theLevel) +{ + for (int aLevelIndex = myAlertLevels.Size(); aLevelIndex >= 1; aLevelIndex--) + { + Message_Level* aLevel = myAlertLevels.Value (aLevelIndex); + myAlertLevels.Remove (aLevelIndex); + + if (aLevel == theLevel) + return; + } +} + +//======================================================================= +//function : Clear +//purpose : +//======================================================================= + +void Message_Report::Clear() +{ + if (compositeAlerts().IsNull()) + return; + + compositeAlerts()->Clear(); + myAlertLevels.Clear(); } //======================================================================= @@ -125,9 +233,11 @@ void Message_Report::Clear () void Message_Report::Clear (Message_Gravity theGravity) { - Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), - "Requesting alerts for gravity not in valid range", ); - myAlerts[theGravity].Clear(); + if (compositeAlerts().IsNull()) + return; + + compositeAlerts()->Clear (theGravity); + myAlertLevels.Clear(); } //======================================================================= @@ -137,20 +247,28 @@ void Message_Report::Clear (Message_Gravity theGravity) void Message_Report::Clear (const Handle(Standard_Type)& theType) { - for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i) - { - for (Message_ListOfAlert::Iterator anIt (myAlerts[i]); anIt.More(); ) - { - if (anIt.Value().IsNull() || anIt.Value()->IsInstance (theType)) - { - myAlerts[i].Remove (anIt); - } - else - { - anIt.More(); - } - } - } + if (compositeAlerts().IsNull()) + return; + + compositeAlerts()->Clear (theType); + myAlertLevels.Clear(); +} + +//======================================================================= +//function : SetActiveMetric +//purpose : +//======================================================================= + +void Message_Report::SetActiveMetric (const Message_MetricType theMetricType, + const Standard_Boolean theActivate) +{ + if (theActivate == myActiveMetrics.Contains (theMetricType)) + return; + + if (theActivate) + myActiveMetrics.Add (theMetricType); + else + myActiveMetrics.Remove (theMetricType); } //======================================================================= @@ -160,9 +278,9 @@ void Message_Report::Clear (const Handle(Standard_Type)& theType) void Message_Report::Dump (Standard_OStream& theOS) { - for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity) + for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter) { - Dump (theOS, (Message_Gravity)iGravity); + Dump (theOS, (Message_Gravity)aGravIter); } } @@ -173,19 +291,13 @@ void Message_Report::Dump (Standard_OStream& theOS) void Message_Report::Dump (Standard_OStream& theOS, Message_Gravity theGravity) { - Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), - "Requesting alerts for gravity not in valid range", ); + if (compositeAlerts().IsNull()) + return; - // report each type of warning only once - NCollection_Map aPassedAlerts; - for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next()) - { - if (aPassedAlerts.Add (anIt.Value()->DynamicType())) - { - Message_Msg aMsg (anIt.Value()->GetMessageKey()); - theOS << aMsg.Original() << std::endl; - } - } + if (compositeAlerts().IsNull()) + return; + + dumpMessages (theOS, theGravity, compositeAlerts()); } //======================================================================= @@ -195,9 +307,9 @@ void Message_Report::Dump (Standard_OStream& theOS, Message_Gravity theGravity) void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger) { - for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity) + for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter) { - SendMessages (theMessenger, (Message_Gravity)iGravity); + SendMessages (theMessenger, (Message_Gravity)aGravIter); } } @@ -208,19 +320,10 @@ void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger, Message_Gravity theGravity) { - Standard_ASSERT_RETURN (theGravity >= 0 && size_t(theGravity) < sizeof(myAlerts)/sizeof(myAlerts[0]), - "Requesting alerts for gravity not in valid range", ); + if (compositeAlerts().IsNull()) + return; - // report each type of warning only once - NCollection_Map aPassedAlerts; - for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next()) - { - if (aPassedAlerts.Add (anIt.Value()->DynamicType())) - { - Message_Msg aMsg (anIt.Value()->GetMessageKey()); - theMessenger->Send (aMsg, theGravity); - } - } + sendMessages (theMessenger, theGravity, compositeAlerts()); } //======================================================================= @@ -230,9 +333,9 @@ void Message_Report::SendMessages (const Handle(Message_Messenger)& theMessenger void Message_Report::Merge (const Handle(Message_Report)& theOther) { - for (int iGravity = Message_Trace; iGravity <= Message_Fail; ++iGravity) + for (int aGravIter = Message_Trace; aGravIter <= Message_Fail; ++aGravIter) { - Merge (theOther, (Message_Gravity)iGravity); + Merge (theOther, (Message_Gravity)aGravIter); } } @@ -248,3 +351,78 @@ void Message_Report::Merge (const Handle(Message_Report)& theOther, Message_Grav AddAlert (theGravity, anIt.Value()); } } + +//======================================================================= +//function : ñompositeAlerts +//purpose : +//======================================================================= +const Handle(Message_CompositeAlerts)& Message_Report::compositeAlerts (const Standard_Boolean isCreate) +{ + if (myCompositAlerts.IsNull() && isCreate) + myCompositAlerts = new Message_CompositeAlerts(); + + return myCompositAlerts; +} + +//======================================================================= +//function : sendMessages +//purpose : +//======================================================================= + +void Message_Report::sendMessages (const Handle(Message_Messenger)& theMessenger, Message_Gravity theGravity, + const Handle(Message_CompositeAlerts)& theCompositeAlert) +{ + if (theCompositeAlert.IsNull()) + return; + + const Message_ListOfAlert& anAlerts = theCompositeAlert->Alerts (theGravity); + // report each type of warning only once + //NCollection_Map aPassedAlerts; + for (Message_ListOfAlert::Iterator anIt (anAlerts); anIt.More(); anIt.Next()) + { + //if (aPassedAlerts.Add (anIt.Value()->DynamicType())) + { + //Message_Msg aMsg (anIt.Value()->GetMessageKey()); + //theMessenger->Send (aMsg, theGravity); + theMessenger->Send (anIt.Value()->GetMessageKey(), theGravity); + } + Handle(Message_AlertExtended) anExtendedAlert = Handle(Message_AlertExtended)::DownCast (anIt.Value()); + if (anExtendedAlert.IsNull()) + continue; + + Handle(Message_CompositeAlerts) aCompositeAlerts = anExtendedAlert->CompositeAlerts(); + if (aCompositeAlerts.IsNull()) + continue; + + sendMessages (theMessenger, theGravity, aCompositeAlerts); + } +} + +//======================================================================= +//function : dumpMessages +//purpose : +//======================================================================= +void Message_Report::dumpMessages (Standard_OStream& theOS, Message_Gravity theGravity, + const Handle(Message_CompositeAlerts)& theCompositeAlert) +{ + if (theCompositeAlert.IsNull()) + return; + + const Message_ListOfAlert& anAlerts = theCompositeAlert->Alerts (theGravity); + // report each type of war++ning only once + //NCollection_Map aPassedAlerts; + for (Message_ListOfAlert::Iterator anIt (anAlerts); anIt.More(); anIt.Next()) + { + //if (aPassedAlerts.Add (anIt.Value()->DynamicType())) + { + //Message_Msg aMsg (anIt.Value()->GetMessageKey()); + //theOS << aMsg.Original() << std::endl; + theOS << anIt.Value()->GetMessageKey() << std::endl; + } + + Handle(Message_AlertExtended) anExtendedAlert = Handle(Message_AlertExtended)::DownCast (anIt.Value()); + if (anExtendedAlert.IsNull()) + continue; + dumpMessages (theOS, theGravity, anExtendedAlert->CompositeAlerts()); + } +} diff --git a/src/Message/Message_Report.hxx b/src/Message/Message_Report.hxx index 8440ba8149..292600bd39 100644 --- a/src/Message/Message_Report.hxx +++ b/src/Message/Message_Report.hxx @@ -17,13 +17,18 @@ #define _Message_Report_HeaderFile #include +#include #include +#include +#include +#include #include +class Message_CompositeAlerts; class Message_Messenger; - class Message_Report; -DEFINE_STANDARD_HANDLE(Message_Report, MMgt_TShared) + +DEFINE_STANDARD_HANDLE(Message_Report, Standard_Transient) //! Container for alert messages, sorted according to their gravity. //! @@ -46,6 +51,8 @@ DEFINE_STANDARD_HANDLE(Message_Report, MMgt_TShared) //! Dump() or in more advanced way, by iterating over lists returned by GetAlerts() //! //! - Report can be cleared by methods Clear() (usually after reporting) +//! +//! Message_PrinterToReport is a printer in Messenger to convert data sent to messenger into report class Message_Report : public Standard_Transient { @@ -67,6 +74,22 @@ public: //! Returns true if specific type of alert is recorded with specified gravity Standard_EXPORT Standard_Boolean HasAlert (const Handle(Standard_Type)& theType, Message_Gravity theGravity); + //! Returns true if a report printer for the current report is registered in the messenger + // @param theMessenger the messenger. If it's NULL, the default messenger is used + Standard_EXPORT Standard_Boolean IsActiveInMessenger (const Handle(Message_Messenger)& theMessenger = NULL) const; + + //! Creates an instance of Message_PrinterToReport with the current report and register it in messenger + //! @param toActivate if true, activated else deactivated + // @param theMessenger the messenger. If it's NULL, the default messenger is used + Standard_EXPORT void ActivateInMessenger (const Standard_Boolean toActivate, const Handle(Message_Messenger)& theMessenger = NULL) const; + + //! Add new level of alerts + //! @param theLevel a level + Standard_EXPORT void AddLevel (Message_Level* theLevel); + + //! Remove level of alerts + Standard_EXPORT void RemoveLevel (Message_Level* theLevel); + //! Clears all collected alerts Standard_EXPORT void Clear (); @@ -76,6 +99,25 @@ public: //! Clears collected alerts with specified type Standard_EXPORT void Clear (const Handle(Standard_Type)& theType); + //! Returns computed metrics when alerts are performed + const NCollection_Map& ActiveMetrics() const { return myActiveMetrics; } + + //! Sets metrics to compute when alerts are performed + //! @param theMetrics container of metrics + Standard_EXPORT void SetActiveMetric (const Message_MetricType theMetricType, const Standard_Boolean theActivate); + + //! Removes all activated metrics + void ClearMetrics() { myActiveMetrics.Clear(); } + + //! Returns maximum number of collecting alerts. If the limit is achieved, + //! first alert is removed, the new alert is added in the container. + //! @return the limit value + Standard_Integer Limit() const { return myLimit; } + + //! Sets maximum number of collecting alerts. + //! @return theLimit limit value + void SetLimit(const Standard_Integer theLimit) { myLimit = theLimit; } + //! Dumps all collected alerts to stream Standard_EXPORT void Dump (Standard_OStream& theOS); @@ -94,15 +136,31 @@ public: //! Merges alerts with specified gravity from theOther report into this Standard_EXPORT void Merge (const Handle(Message_Report)& theOther, Message_Gravity theGravity); - // OCCT RTTI DEFINE_STANDARD_RTTIEXT(Message_Report,Standard_Transient) +protected: + //! Returns class provided hierarchy of alerts if created or create if the parameter is true + //! @param isCreate if composite alert has not been created for this alert, it should be created + //! @return instance or NULL + Standard_EXPORT const Handle(Message_CompositeAlerts)& compositeAlerts (const Standard_Boolean isCreate = Standard_False); + + //! Sends alerts to messenger + Standard_EXPORT void sendMessages (const Handle(Message_Messenger)& theMessenger, Message_Gravity theGravity, + const Handle(Message_CompositeAlerts)& theCompositeAlert); + + //! Dumps collected alerts with specified gravity to stream + Standard_EXPORT void dumpMessages (Standard_OStream& theOS, Message_Gravity theGravity, + const Handle(Message_CompositeAlerts)& theCompositeAlert); + protected: Standard_Mutex myMutex; - // store messages in a lists sorted by gravity; - // here we rely on knowledge that Message_Fail is the last element of the enum - Message_ListOfAlert myAlerts[Message_Fail + 1]; + Handle(Message_CompositeAlerts) myCompositAlerts; //! container of alerts + + NCollection_Sequence myAlertLevels; //! container of active levels, new alerts are added below the latest level + NCollection_Map myActiveMetrics; //! metrics to compute on alerts + + Standard_Integer myLimit; //! Maximum number of collected alerts on the top level }; #endif // _Message_Report_HeaderFile diff --git a/src/XmlDrivers/FILES b/src/XmlDrivers/FILES index 058b8acc20..d4a93d94ff 100644 --- a/src/XmlDrivers/FILES +++ b/src/XmlDrivers/FILES @@ -4,3 +4,5 @@ XmlDrivers_DocumentRetrievalDriver.cxx XmlDrivers_DocumentRetrievalDriver.hxx XmlDrivers_DocumentStorageDriver.cxx XmlDrivers_DocumentStorageDriver.hxx +XmlDrivers_MessageReportStorage.cxx +XmlDrivers_MessageReportStorage.hxx diff --git a/src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx b/src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx new file mode 100644 index 0000000000..c0d1088e2a --- /dev/null +++ b/src/XmlDrivers/XmlDrivers_MessageReportStorage.cxx @@ -0,0 +1,333 @@ +// Created on: 2018-06-10 +// Created by: Natalia Ermolaeva +// Copyright (c) 2001-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// ======================================================================= +// function : GetApplication +// purpose : +// ======================================================================= + +const Handle(TDocStd_Application)& GetApplication() +{ + static Handle(TDocStd_Application) anApp; + if (anApp.IsNull()) + { + anApp = new TDocStd_Application; + XmlDrivers::DefineFormat (anApp); + } + return anApp; +} + +// ======================================================================= +// function : ExportReport +// purpose : +// ======================================================================= + +void XmlDrivers_MessageReportStorage::ExportReport (const Handle(Message_Report)& theReport, + const TCollection_AsciiString& theFileName) +{ + if (theReport.IsNull()) + return; + + Handle(TDocStd_Document) aDocument; + GetApplication()->NewDocument (TCollection_ExtendedString ("XmlOcaf"), aDocument); + + TDF_Label aMainLabel = aDocument->Main(); + + for (int aGravityId = Message_Trace; aGravityId <= Message_Fail; aGravityId++) + { + Message_Gravity aGravity = (Message_Gravity)aGravityId; + + if (theReport->GetAlerts (aGravity).Size() == 0) + continue; + // Gravity Label + TDF_Label aGravityLabel = aMainLabel.NewChild(); + // set gravity kind string + TCollection_ExtendedString aName (aGravity); + if (!aName.IsEmpty()) + TDataStd_Name::Set (aGravityLabel, aName); + + /// reserved label to store gravity information + //TDF_Label aFirstAlertLabel = aGravityLabel.NewChild(); + + // Alert Labels: labels are started from the second index + const Message_ListOfAlert& anAlerts = theReport->GetAlerts (aGravity); + for (Message_ListOfAlert::Iterator anAlertsIt (anAlerts); anAlertsIt.More(); anAlertsIt.Next()) + { + exportAlert (anAlertsIt.Value(), aGravityLabel); + } + } + GetApplication()->SaveAs (aDocument, theFileName); + GetApplication()->Close (aDocument); +} + +// ======================================================================= +// function : ImportReport +// purpose : +// ======================================================================= + +Handle(Message_Report) XmlDrivers_MessageReportStorage::ImportReport (const TCollection_AsciiString& theFileName) +{ + Handle(TDocStd_Application) anApplication = GetApplication(); + Standard_Integer aDocumentId = anApplication->IsInSession (theFileName); + if (aDocumentId > 0) + { + Handle(TDocStd_Document) aDocument; + anApplication->GetDocument (aDocumentId, aDocument); + anApplication->Close (aDocument); + } + + Handle(TDocStd_Document) aDocument; + GetApplication()->Open (theFileName, aDocument); + if (aDocument.IsNull()) + return Handle(Message_Report)(); + + TDF_Label aMainLabel = aDocument->Main(); + if (aMainLabel.IsNull()) + return Handle(Message_Report)(); + + TDF_Label aLabel; + Handle(Message_Report) aReport = new Message_Report(); + for (TDF_ChildIterator aLabelsIt(aMainLabel); aLabelsIt.More(); aLabelsIt.Next()) + { + TDF_Label aGravityLabel = aLabelsIt.Value(); + if (aGravityLabel.IsNull()) + continue; + Handle(TDF_Attribute) anAttribute; + if (!aGravityLabel.FindAttribute (TDataStd_Name::GetID(), anAttribute)) + continue; + Handle(TDataStd_Name) aNameAttribute = Handle(TDataStd_Name)::DownCast (anAttribute); + if (aNameAttribute.IsNull()) + continue; + + // get gravity type + const TCollection_ExtendedString& aGravityName = aNameAttribute->Get(); + Message_Gravity aGravity = (Message_Gravity) (TCollection_AsciiString (aGravityName).IntegerValue()); + + /// reserved label to store gravity information + //TDF_Label aFirstAlertLabel = aGravityLabel.FindChild (1, Standard_False); + + // find alerts information, add corresponded alerts to the report + for (TDF_ChildIterator anAlertLabelsIt (aGravityLabel); anAlertLabelsIt.More(); anAlertLabelsIt.Next()) + { + TDF_Label anAlertLabel = anAlertLabelsIt.Value(); + if (anAlertLabel.IsNull()) + continue; + + importAlert (anAlertLabel, aGravity, aReport, Handle(Message_Alert)()); + } + } + return aReport; +} + +// ======================================================================= +// function : exportAlert +// purpose : +// ======================================================================= + +void XmlDrivers_MessageReportStorage::exportAlert (const Handle(Message_Alert)& theAlert, const TDF_Label& theParentLabel) +{ + TDF_Label anAlertLabel = theParentLabel.NewChild(); + TDataStd_Name::Set (anAlertLabel, theAlert->DynamicType()->Name()); + + /// reserved label to store parameters of the current label + TDF_Label anAlertParmetersLabel = anAlertLabel.NewChild(); + exportAlertParameters (theAlert, anAlertParmetersLabel); + + for (int aGravityId = Message_Trace; aGravityId <= Message_Fail; aGravityId++) + { + // Gravity Label + TDF_Label aGravityLabel = anAlertLabel.NewChild(); + // set gravity kind string + TDataStd_Name::Set (aGravityLabel, aGravityId); + + Handle(Message_AlertExtended) anAlertExtended = Handle(Message_AlertExtended)::DownCast (theAlert); + if (anAlertExtended.IsNull()) + continue; + Handle(Message_CompositeAlerts) aComposite = anAlertExtended->CompositeAlerts(); + if (aComposite.IsNull()) + continue; + + const Message_ListOfAlert& anAlerts = aComposite->Alerts ((Message_Gravity)aGravityId); + for (Message_ListOfAlert::Iterator anAlertsIt (anAlerts); anAlertsIt.More(); anAlertsIt.Next()) + exportAlert (anAlertsIt.Value(), aGravityLabel); + } +} + +// ======================================================================= +// function : importAlert +// purpose : +// ======================================================================= + +void XmlDrivers_MessageReportStorage::importAlert (const TDF_Label& theAlertLabel, + const Message_Gravity theGravity, + Handle(Message_Report)& theReport, + const Handle(Message_Alert)& theParentAlert) +{ + TDF_Label aParametersLabel = theAlertLabel.FindChild (1, Standard_False); + Handle(Message_Alert) anAlert = importAlertParameters (aParametersLabel); + if (anAlert.IsNull()) + return; + + TDF_Label aLabel; + TDF_ChildIterator aSubAlertsLabelsIt (theAlertLabel); + aSubAlertsLabelsIt.Next(); // do not processing the first (parameters) label + for (; aSubAlertsLabelsIt.More(); aSubAlertsLabelsIt.Next()) + { + TDF_Label aGravityLabel = aSubAlertsLabelsIt.Value(); + if (aGravityLabel.IsNull()) + continue; + Handle(TDF_Attribute) anAttribute; + if (!aGravityLabel.FindAttribute (TDataStd_Name::GetID(), anAttribute)) + continue; + Handle(TDataStd_Name) aNameAttribute = Handle(TDataStd_Name)::DownCast (anAttribute); + if (aNameAttribute.IsNull()) + continue; + + // get gravity type + Message_Gravity aGravity = (Message_Gravity) (TCollection_AsciiString (aNameAttribute->Get()).IntegerValue()); + // find alerts information, add corresponded alerts to the report + for (TDF_ChildIterator anAlertLabelsIt (aGravityLabel); anAlertLabelsIt.More(); anAlertLabelsIt.Next()) + { + TDF_Label anAlertLabel = anAlertLabelsIt.Value(); + if (anAlertLabel.IsNull()) + continue; + + importAlert (anAlertLabel, aGravity, theReport, anAlert); + } + } + if (theParentAlert.IsNull()) + theReport->AddAlert (theGravity, anAlert); + else + { + MESSAGE_ADD_LEVEL_SENTRY + theReport->AddAlert (theGravity, anAlert); + } +} + +// ======================================================================= +// function : exportAlertParameters +// purpose : +// ======================================================================= +void XmlDrivers_MessageReportStorage::exportAlertParameters (const Handle(Message_Alert)& theAlert, const TDF_Label& theAlertLabel) +{ + Handle(Message_AlertExtended) anAlertExtended = Handle(Message_AlertExtended)::DownCast (theAlert); + if (anAlertExtended.IsNull()) // name attribute is empty + return; + + // store attribute time + Handle(Message_Attribute) anAttribute = anAlertExtended->Attribute(); + + TDataStd_Name::Set (theAlertLabel, anAttribute->DynamicType()->Name()); + //TDataStd_Real::Set (theAlertLabel, anAlertExtended->CumulativeMetric()); + + TDataStd_AsciiString::Set (theAlertLabel, anAttribute->GetName()); + + Standard_CString aDynamicTypeName = anAttribute->DynamicType()->Name(); + if (aDynamicTypeName == STANDARD_TYPE (Message_AttributeStream)->Name()) + { + Handle(Message_AttributeStream) aValuesArrayAlert = Handle(Message_AttributeStream)::DownCast (anAttribute); + // store values + TCollection_AsciiString aStreamText = Standard_Dump::Text (aValuesArrayAlert->Stream()); + if (aStreamText.IsEmpty()) + return; + Handle(TDataStd_ExtStringArray) aListAttribute = TDataStd_ExtStringArray::Set (theAlertLabel, 0, 0); + aListAttribute->SetValue (0, aStreamText); + } +} + +// ======================================================================= +// function : importAlertParameters +// purpose : +// ======================================================================= +Handle(Message_Alert) XmlDrivers_MessageReportStorage::importAlertParameters (const TDF_Label& aParametersLabel) +{ + Handle(TDF_Attribute) anAttribute; + if (!aParametersLabel.FindAttribute (TDataStd_Name::GetID(), anAttribute)) + return Handle(Message_Alert)(); + + Handle(TDataStd_Name) aDynamicTypeAttribute = Handle(TDataStd_Name)::DownCast (anAttribute); + if (aDynamicTypeAttribute.IsNull()) + return Handle(Message_Alert)(); + const TCollection_ExtendedString& aDynamicTypeName = aDynamicTypeAttribute->Get(); + + Handle(Message_AlertExtended) anAlert = new Message_AlertExtended(); + Handle(Message_Attribute) aMessageAttribute; + if (aDynamicTypeName == STANDARD_TYPE (Message_Attribute)->Name()) + aMessageAttribute = new Message_Attribute(); + else if (aDynamicTypeName == STANDARD_TYPE (Message_AttributeStream)->Name()) + { + // values + NCollection_Vector anArrayValues; + if (!aParametersLabel.FindAttribute (TDataStd_ExtStringArray::GetID(), anAttribute)) + return Handle(Message_Alert)(); + + Handle(TDataStd_ExtStringArray) aValuesAttribute = Handle(TDataStd_ExtStringArray)::DownCast (anAttribute); + if (aValuesAttribute.IsNull()) + return Handle(Message_Alert)(); + + Standard_SStream aStream; + for (int aValueId = aValuesAttribute->Lower(); aValueId <= aValuesAttribute->Upper(); aValueId++) + { + aStream << aValuesAttribute->Value (aValueId); + } + aMessageAttribute = new Message_AttributeStream (aStream); + } + + if (!aMessageAttribute.IsNull()) + { + // name + if (!aParametersLabel.FindAttribute (TDataStd_AsciiString::GetID(), anAttribute)) + return Handle(Message_Alert)(); + Handle(TDataStd_AsciiString) aNameAttribute = Handle(TDataStd_AsciiString)::DownCast (anAttribute); + if (aNameAttribute.IsNull()) + return Handle(Message_Alert)(); + + aMessageAttribute->SetName (aNameAttribute->Get()); + anAlert->SetAttribute (aMessageAttribute); + } + + // time + //Standard_Real aTime = -1; + //Handle(TDataStd_Real) aTimeAttribute; + //if (aParametersLabel.FindAttribute (TDataStd_Real::GetID(), aTimeAttribute)) + // aTime = aTimeAttribute->Get(); + + //anAlert->SetCumulativeMetric (aTime); + return anAlert; +} diff --git a/src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx b/src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx new file mode 100644 index 0000000000..81e1db8f9c --- /dev/null +++ b/src/XmlDrivers/XmlDrivers_MessageReportStorage.hxx @@ -0,0 +1,74 @@ +// Created on: 2018-06-10 +// Created by: Natalia Ermolaeva +// Copyright (c) 2001-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _XmlDrivers_MessageReportStorage +#define _XmlDrivers_MessageReportStorage + +#include + +#include +#include +#include + +//! Base class to store/restore Message_Report content in XML document +class XmlDrivers_MessageReportStorage +{ +public: + //! Create document for the report + //! \param theReport the source report + //! \param theFileName a file name + Standard_EXPORT static void ExportReport (const Handle(Message_Report)& theReport, const TCollection_AsciiString& theFileName); + + //! Restores document file content into report instance + //! \param theFileName a file name + //! \return new report or NULL + Standard_EXPORT static Handle(Message_Report) ImportReport (const TCollection_AsciiString& theFileName); + +private: + //! Create labels/attributes for the alert and place it under the parent label. + //! It is recursive as alerts may contains other alerts + //! \param theAlert a source alert + //! \parm theParentLabel a label where alert label is placed + static void exportAlert (const Handle(Message_Alert)& theAlert, const TDF_Label& theParentLabel); + + //! Creates a new alert by the label parameters + //! \param theAlertLabel a source document label + //! \param theGravity an alert gravity + //! \param theReport a container of alerts + //! \param theParentAlert a parent alert, if null, the parent is report + static void importAlert (const TDF_Label& theAlertLabel, + const Message_Gravity theGravity, + Handle(Message_Report)& theReport, + const Handle(Message_Alert)& theParentAlert); + + //! Convert alert to a custom type and store parameters in child labels and attributes + //! \param theAlert a source alert + //! \parm theAlertLabel an alert label + static void exportAlertParameters (const Handle(Message_Alert)& theAlert, + const TDF_Label& theAlertLabel); + + //! Creates alert by label type filled by the label content + //! \param theParametersLabel a label + //! \return new alert or NULL + static Handle(Message_Alert) importAlertParameters (const TDF_Label& aParametersLabel); +}; + +#define MESSAGE_STORE_XML_REPORT(FileName) \ +{ \ + Handle(Message_Report) aReport = Message::DefaultReport (Standard_False); \ + if (!aReport.IsNull()) XmlDrivers_MessageReportStorage::ExportReport (aReport, FileName); \ +} + +#endif // _XmlDrivers_MessageReportStorage -- 2.39.5