]> OCCT Git - occt.git/commitdiff
0029451: Information Message Alert to debug an algorithm or object functionality IR-2020-10-02
authornds <nds@opencascade.com>
Fri, 2 Oct 2020 11:17:59 +0000 (14:17 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 2 Oct 2020 17:45:29 +0000 (20:45 +0300)
- Added possibility to send stream information and transient object into Message_Messenger. Message_Printer will process it if needed.
- Add Message_PrinterToReport to send messenger information into Message_Report.
- Extended Message_Report to collect hierarchical alerts, to be able to collect some metrics during alerts processing.
- Added Message_AlertExtended to prepare hierarchical alerts with custom attributes. One attribute for one alert.
- Added Message_CompositeAlerts class to handle a container of alerts.
- Added Message_Level to start a new hierarchical level by creating an instance, stop by destricting.
- Added Message_Attribute and inheritors to store custom information about alert like object, stream, shape, some metrics.
- Implement Message_AttributeAlert to collect start/stop information about active metrics of Message_Report. This kind of attribute is created if at least one metric is active in the report.
- Add Message_MetricType enumeration with possible kinds of metrics in report.
- Implement DumpJson for Message_Report to store all collected alerts into stream.
- Added draw commands for Message_Report, Message_Messenger.

37 files changed:
src/Draw/Draw.cxx
src/Draw/Draw.hxx
src/Draw/Draw_Commands.cxx
src/Draw/Draw_MessageCommands.cxx [new file with mode: 0644]
src/Draw/FILES
src/Message/FILES
src/Message/Message.cxx
src/Message/Message.hxx
src/Message/Message_Alert.cxx
src/Message/Message_Alert.hxx
src/Message/Message_AlertExtended.cxx [new file with mode: 0644]
src/Message/Message_AlertExtended.hxx [new file with mode: 0644]
src/Message/Message_Attribute.cxx [new file with mode: 0644]
src/Message/Message_Attribute.hxx [new file with mode: 0644]
src/Message/Message_AttributeMeter.cxx [new file with mode: 0644]
src/Message/Message_AttributeMeter.hxx [new file with mode: 0644]
src/Message/Message_AttributeObject.cxx [new file with mode: 0644]
src/Message/Message_AttributeObject.hxx [new file with mode: 0644]
src/Message/Message_AttributeStream.cxx [new file with mode: 0644]
src/Message/Message_AttributeStream.hxx [new file with mode: 0644]
src/Message/Message_CompositeAlerts.cxx [new file with mode: 0644]
src/Message/Message_CompositeAlerts.hxx [new file with mode: 0644]
src/Message/Message_Level.cxx [new file with mode: 0644]
src/Message/Message_Level.hxx [new file with mode: 0644]
src/Message/Message_Messenger.cxx
src/Message/Message_Messenger.hxx
src/Message/Message_MetricType.hxx [new file with mode: 0644]
src/Message/Message_Printer.cxx
src/Message/Message_Printer.hxx
src/Message/Message_PrinterToReport.cxx [new file with mode: 0644]
src/Message/Message_PrinterToReport.hxx [new file with mode: 0644]
src/Message/Message_Report.cxx
src/Message/Message_Report.hxx
src/TopoDS/FILES
src/TopoDS/TopoDS_AlertAttribute.cxx [new file with mode: 0644]
src/TopoDS/TopoDS_AlertAttribute.hxx [new file with mode: 0644]
tests/demo/draw/messenger [new file with mode: 0644]

index 8dd7e5a7d8541cd4fdd9d81774a9443a24565b2c..3a77a71c6a94f4ee99d5e47d8c4cff0dbb50a4a0 100644 (file)
@@ -425,6 +425,7 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
   // standard commands
   // *****************************************************************
   Draw::BasicCommands(theCommands);
+  Draw::MessageCommands(theCommands);
   Draw::VariableCommands(theCommands);
   Draw::UnitCommands(theCommands);
   if (!Draw_Batch) Draw::GraphicCommands(theCommands);
index cbf0d1fc278717b81e7a039d24d0aa0c2c8d455e..87317b338d106470a3a804ebed494f7c0307365f 100644 (file)
@@ -201,6 +201,9 @@ public: //! @name methods loading standard command sets
   //! Defines Draw basic commands
   Standard_EXPORT static void BasicCommands (Draw_Interpretor& I);
   
+  //! Defines Draw message commands
+  Standard_EXPORT static void MessageCommands (Draw_Interpretor& I);
+
   //! Defines Draw variables handling commands.
   Standard_EXPORT static void VariableCommands (Draw_Interpretor& I);
   
index c375f9eeda033c838cf12c59ae40602f6214d18a..cf291fb0806f64576571ad2faa32c4ffb3b6aa0f 100644 (file)
@@ -23,6 +23,7 @@
 void Draw::Commands (Draw_Interpretor& theCommands)
 {
   Draw::BasicCommands(theCommands);
+  Draw::MessageCommands(theCommands);
   Draw::VariableCommands(theCommands);
   Draw::GraphicCommands(theCommands);
   Draw::PloadCommands(theCommands);
diff --git a/src/Draw/Draw_MessageCommands.cxx b/src/Draw/Draw_MessageCommands.cxx
new file mode 100644 (file)
index 0000000..1e30955
--- /dev/null
@@ -0,0 +1,388 @@
+// 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 <Draw.hxx>
+#include <Draw_Printer.hxx>
+
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_PrinterOStream.hxx>
+#include <Message_PrinterSystemLog.hxx>
+#include <Message_PrinterToReport.hxx>
+#include <Message_Report.hxx>
+#include <NCollection_Shared.hxx>
+#include <Standard_Dump.hxx>
+
+//==============================================================================
+//function : printerType
+//purpose  :
+//==============================================================================
+static Standard_Boolean printerType (const TCollection_AsciiString& theTypeName,
+                                     Handle(Standard_Type)& theType)
+{
+  if (theTypeName == "ostream")
+  {
+    theType = STANDARD_TYPE(Message_PrinterOStream);
+    return Standard_True;
+  }
+  else if (theTypeName == "systemlog")
+  {
+    theType = STANDARD_TYPE(Message_PrinterSystemLog);
+    return Standard_True;
+  }
+  else if (theTypeName == "report")
+  {
+    theType = STANDARD_TYPE(Message_PrinterToReport);
+    return Standard_True;
+  }
+  else if (theTypeName == "draw")
+  {
+    theType = STANDARD_TYPE(Draw_Printer);
+    return Standard_True;
+  }
+
+  return Standard_False;
+}
+
+//==============================================================================
+//function : createPrinter
+//purpose  :
+//==============================================================================
+static Handle(Message_Printer) createPrinter (const Handle(Standard_Type)& theType, Draw_Interpretor& theDI)
+{
+  const TCollection_AsciiString aTypeName (theType->Name());
+  if (aTypeName == STANDARD_TYPE(Message_PrinterOStream)->Name())
+  {
+    return new Message_PrinterOStream();
+  }
+  else if (aTypeName == STANDARD_TYPE(Message_PrinterSystemLog)->Name())
+  {
+    return new Message_PrinterSystemLog ("draw_messages");
+  }
+  else if (aTypeName == STANDARD_TYPE(Message_PrinterToReport)->Name())
+  {
+    Handle(Message_PrinterToReport) aMessagePrinter = new Message_PrinterToReport();
+    const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True);
+    aMessagePrinter->SetReport (aReport);
+    return aMessagePrinter;
+  }
+  else if (aTypeName == STANDARD_TYPE(Draw_Printer)->Name())
+  {
+    return new Draw_Printer (theDI);
+  }
+  return Handle(Message_Printer)();
+}
+
+//==============================================================================
+//function : SendMessage
+//purpose  :
+//==============================================================================
+static Standard_Integer SendMessage (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+{
+  if (theArgNb < 2)
+  {
+    theDI << "Error: wrong number of arguments";
+    return 1;
+  }
+
+  const Handle(Message_Messenger)& aMessenger = Message::DefaultMessenger();
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    aMessenger->Send (anArg);
+  }
+
+  return 0;
+}
+
+//==============================================================================
+//function : PrintMessenger
+//purpose  :
+//==============================================================================
+static Standard_Integer PrintMessenger (Draw_Interpretor& theDI, Standard_Integer, const char**)
+{
+  const Handle(Message_Messenger)& aMessenger = Message::DefaultMessenger();
+
+  Standard_SStream aSStream;
+  aMessenger->DumpJson (aSStream);
+  theDI << aSStream;
+  std::cout << aSStream.str() << std::endl;
+
+  return 0;
+}
+
+//==============================================================================
+//function : SetMessagePrinter
+//purpose  :
+//==============================================================================
+static Standard_Integer SetMessagePrinter (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+{
+  if (theArgNb < 2)
+  {
+    theDI << "Error: wrong number of arguments";
+    return 1;
+  }
+
+  Standard_Boolean toAddPrinter = Standard_True;
+  NCollection_List<TCollection_AsciiString> aPrinterTypes;
+  const Handle(Message_Messenger)& aMessenger = Message::DefaultMessenger();
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anArg == "-state")
+    {
+      if (anArgIter + 1 < theArgNb
+       && Draw::ParseOnOff (theArgVec[anArgIter + 1], toAddPrinter))
+      {
+        ++anArgIter;
+      }
+    }
+    else if (anArg == "-type"
+          && anArgIter + 1 < theArgNb)
+    {
+      TCollection_AsciiString aVal (theArgVec[++anArgIter]);
+      aPrinterTypes.Append (aVal);
+    }
+    else
+    {
+      theDI << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'";
+      return 1;
+    }
+  }
+
+  for (NCollection_List<TCollection_AsciiString>::Iterator anIterator (aPrinterTypes); anIterator.More(); anIterator.Next())
+  {
+    Handle(Standard_Type) aPrinterType;
+    if (!printerType (anIterator.Value(), aPrinterType))
+    {
+      theDI << "Syntax error: unknown printer type '" << anIterator.Value() << "'";
+      return 1;
+    }
+
+    if (toAddPrinter)
+    {
+      Handle(Message_Printer) aPrinter = createPrinter (aPrinterType, theDI);
+      aMessenger->AddPrinter (aPrinter);
+      if (!Handle(Message_PrinterToReport)::DownCast(aPrinter).IsNull())
+      {
+        Message::DefaultReport (Standard_False)->UpdateActiveInMessenger();
+      }
+    }
+    else
+    {
+      aMessenger->RemovePrinters (aPrinterType);
+    }
+  }
+  return 0;
+}
+
+//==============================================================================
+//function : ClearReport
+//purpose  :
+//==============================================================================
+static Standard_Integer ClearReport(Draw_Interpretor& theDI, Standard_Integer theArgNb, const char**)
+{
+  if (theArgNb < 1)
+  {
+    theDI << "Error: wrong number of arguments";
+    return 1;
+  }
+
+  const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_False);
+  if (aReport.IsNull())
+  {
+    theDI << "Error: report is no created";
+    return 1;
+  }
+
+  aReport->Clear();
+  return 0;
+}
+
+//==============================================================================
+//function : SetReportMetric
+//purpose  :
+//==============================================================================
+static Standard_Integer SetReportMetric(Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+{
+  if (theArgNb < 1)
+  {
+    theDI << "Error: wrong number of arguments";
+    return 1;
+  }
+
+  const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_True);
+  if (aReport.IsNull())
+  {
+    return 1;
+  }
+
+  aReport->ClearMetrics();
+  for (int i = 1; i < theArgNb; i++)
+  {
+    Standard_Integer aMetricId = Draw::Atoi (theArgVec[i]);
+    if (aMetricId < Message_MetricType_ThreadCPUUserTime || aMetricId > Message_MetricType_MemHeapUsage)
+    {
+      theDI << "Error: unrecognized message metric: " << aMetricId;
+      return 1;
+    }
+    aReport->SetActiveMetric ((Message_MetricType)aMetricId, Standard_True);
+  }
+  return 0;
+}
+
+//==============================================================================
+//function : CollectMetricMessages
+//purpose  :
+//==============================================================================
+static Standard_Integer CollectMetricMessages(Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+{
+  static Handle(NCollection_Shared<Message_Level>) MyLevel;
+
+  if (theArgNb < 1)
+  {
+    theDI << "Error: wrong number of arguments";
+    return 1;
+  }
+
+  Standard_Boolean toActivate = Standard_False;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anArg == "-activate")
+    {
+      if (anArgIter + 1 < theArgNb
+       && Draw::ParseOnOff (theArgVec[anArgIter + 1], toActivate))
+      {
+        ++anArgIter;
+      }
+    }
+  }
+  if (toActivate)
+  {
+    if (!MyLevel.IsNull())
+    {
+      theDI << "Error: collecting already activated";
+      return 1;
+    }
+    MyLevel = new NCollection_Shared<Message_Level>("Level");
+  }
+  else
+  {
+    if (!MyLevel)
+    {
+      theDI << "Error: collecting was not activated";
+      return 1;
+    }
+    MyLevel.Nullify();
+    MyLevel = 0;
+  }
+  return 0;
+}
+
+//==============================================================================
+//function : PrintReport
+//purpose  :
+//==============================================================================
+static Standard_Integer PrintReport(Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
+{
+  if (theArgNb < 1)
+  {
+    theDI << "Error: wrong number of arguments";
+    return 1;
+  }
+
+  const Handle(Message_Report)& aReport = Message::DefaultReport (Standard_False);
+  if (aReport.IsNull())
+  {
+    theDI << "Error: report is no created";
+    return 1;
+  }
+
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArgCase (theArgVec[anArgIter]);
+    anArgCase.LowerCase();
+    if (anArgCase == "-messenger")
+    {
+      aReport->SendMessages (Message::DefaultMessenger());
+    }
+    else if (anArgCase == "-dump"
+          || anArgCase == "-print")
+    {
+      Standard_SStream aSStream;
+      aReport->Dump (aSStream);
+      theDI << aSStream;
+    }
+    else if (anArgCase == "-dumpjson")
+    {
+      Standard_SStream aSStream;
+      aReport->DumpJson (aSStream);
+      theDI << aSStream;
+    }
+  }
+
+  return 0;
+}
+
+void Draw::MessageCommands(Draw_Interpretor& theCommands)
+{
+  static Standard_Boolean Done = Standard_False;
+  if (Done) return;
+  Done = Standard_True;
+
+  const char* group = "DRAW Message Commands";
+
+  theCommands.Add("PrintMessenger",
+    "PrintMessenger"
+    "\n\t\t: Prints DumpJson information about messenger.",
+    __FILE__, PrintMessenger, group);
+
+  theCommands.Add("SetMessagePrinter",
+    "SetMessagePrinter [-type ostream|systemlog|report|draw] [-state {on|off}=on]"
+    "\n\t\t: Sets or removes the printer in messenger."
+    "\n\t\t: Option -type set type of printer. Printers are applied with And combination."
+    "\n\t\t: Option -state add or remove printer",
+    __FILE__, SetMessagePrinter, group);
+
+  theCommands.Add("SendMessage",
+    "SendMessage text [text ...]"
+    "\n Sends the text into the messenger.\n",
+    __FILE__, SendMessage, group);
+
+  theCommands.Add("ClearReport",
+    "Removes all alerts in default printer",
+    __FILE__, ClearReport, group);
+
+  theCommands.Add("SetReportMetric",
+    "SetReportMetric [metric ...] \n Activate report metrics, deactivate all if there are no parameters.\n"
+    "\n\t\t: metric is a value of Message_MetricType, e.g. 1 is Message_MetricType_UserTimeCPU" ,
+    __FILE__, SetReportMetric, group);
+
+  theCommands.Add("CollectMetricMessages",
+    "CollectMetricMessages [-activate {0|1}]"
+    "\n Start metric collection by 1, stop by 0. Result is placed in metric attributes of message report.\n",
+    __FILE__, CollectMetricMessages, group);
+  
+  theCommands.Add("PrintReport",
+    "PrintReport [-messenger] [-dump] [-dumpJson]"
+    "\n\t\t: Send report content to default messenger or stream"
+    "\n\t\t: Output options:"
+    "\n\t\t:   -messenger Prints the information about report into messenger."
+    "\n\t\t:   -dump      Prints Dump information about report."
+    "\n\t\t:   -dumpJson  Prints DumpJson information about report.",
+    __FILE__, PrintReport, group);
+}
index c43b33613f43e599cdfcdedc133bb35de457df48..479b683ce97decccb9801c4d52044ce50138599a 100755 (executable)
@@ -43,6 +43,7 @@ Draw_Marker2D.hxx
 Draw_Marker3D.cxx
 Draw_Marker3D.hxx
 Draw_MarkerShape.hxx
+Draw_MessageCommands.cxx
 Draw_Number.cxx
 Draw_Number.hxx
 Draw_PInterp.hxx
index bc275cea11def4a68b7436b9d52787366e15c004..1f553d28bfaa3904a411356e959a7edfbe2c6627 100755 (executable)
@@ -1,16 +1,33 @@
 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.cxx
+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 +39,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_ProgressRange.hxx
@@ -30,8 +49,6 @@ Message_ProgressSentry.hxx
 Message_SequenceOfPrinters.hxx
 Message_Status.hxx
 Message_StatusType.hxx
-Message_Alert.cxx
-Message_Alert.hxx
 Message_ListOfAlert.hxx
 Message_Report.cxx
 Message_Report.hxx
index b540ae5fb291a83a530de83e54e994db0e7cd51b..9dc3a7107e7a952aebae9fb391bcb20bfb510859 100644 (file)
 
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
+#include <Message_Report.hxx>
 #include <TCollection_AsciiString.hxx>
 
 #include <stdio.h>
 #include <string.h>
+
+namespace
+{
+  static Standard_CString Message_Table_PrintMetricTypeEnum[10] =
+  {
+    "NONE", "UserTimeCPU", "SystemTimeInfo", "MemPrivate", "MemVirtual",
+    "MemWorkingSet", "MemWorkingSetPeak", "MemSwapUsage", "MemSwapUsagePeak", "MemHeapUsage"
+  };
+}
+
 //=======================================================================
 //function : DefaultMessenger
 //purpose  : 
@@ -49,3 +60,86 @@ TCollection_AsciiString Message::FillTime (const Standard_Integer hour,
     Sprintf (t, "%.2fs", second);
   return TCollection_AsciiString (t);
 }
+
+//=======================================================================
+//function : DefaultReport
+//purpose  :
+//=======================================================================
+const Handle(Message_Report)& Message::DefaultReport(const Standard_Boolean theToCreate)
+{
+  static Handle(Message_Report) MyReport;
+  if (MyReport.IsNull() && theToCreate)
+  {
+    MyReport = new Message_Report();
+  }
+  return MyReport;
+}
+
+//=======================================================================
+//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;
+    default: return Standard_False;
+  }
+  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;
+}
index 19ec2d8c7a4e3875f6770894daf0e0974c62e428..b4a461b09500b160ccc4df2f0a3ac4dbc5768847 100644 (file)
 #define _Message_HeaderFile
 
 #include <Message_Messenger.hxx>
+#include <Message_Gravity.hxx>
+#include <Message_MetricType.hxx>
+#include <NCollection_Vector.hxx>
+#include <OSD_MemInfo.hxx>
+
+#include <TCollection_AsciiString.hxx>
+
+class Message_Report;
 
 //! Defines
 //! - tools to work with messages
@@ -76,6 +84,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);
 
+public:
+  //! returns the only one instance of Report
+  //! When theToCreate is true - automatically creates message report when not exist.
+  Standard_EXPORT static const Handle(Message_Report)& DefaultReport (const Standard_Boolean theToCreate = Standard_False);
+
+  //! 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);
+
 };
 
 #endif // _Message_HeaderFile
index 5901a49a096237fc29cc2676ea2f6f4828196e0c..c9148aa9730752b9475b772b6fa0df2751444666 100644 (file)
@@ -14,6 +14,7 @@
 // commercial license or contractual agreement.
 
 #include <Message_Alert.hxx>
+#include <Standard_Dump.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Message_Alert,Standard_Transient)
 
@@ -48,3 +49,12 @@ Standard_Boolean Message_Alert::Merge (const Handle(Message_Alert)& /*theTarget*
   // by default, merge trivially
   return Standard_True;
 }
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_Alert::DumpJson (Standard_OStream& theOStream, Standard_Integer) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+}
index 030efb0f99d51125c8adc02fd574020806ba4dea..8d11f2b7e057da9c1d3a1dccd1e2b40730717acc 100644 (file)
@@ -54,6 +54,9 @@ public:
   //! Base implementation always returns true.
   virtual Standard_EXPORT Standard_Boolean Merge (const Handle(Message_Alert)& theTarget);
   
+  //! Dumps the content of me into the stream
+  virtual Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
+
   // 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 (file)
index 0000000..d66892c
--- /dev/null
@@ -0,0 +1,116 @@
+// 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 <Message_AlertExtended.hxx>
+
+#include <Message_Attribute.hxx>
+#include <Message_CompositeAlerts.hxx>
+#include <Message_Report.hxx>
+
+#include <Precision.hxx>
+#include <Standard_Assert.hxx>
+#include <Standard_Dump.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AlertExtended, Message_Alert)
+
+//=======================================================================
+//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;
+}
+
+//=======================================================================
+//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 : DumpJson
+//purpose  :
+//=======================================================================
+void Message_AlertExtended::DumpJson (Standard_OStream& theOStream,
+                                      Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+
+  if (!myCompositAlerts.IsNull())
+  {
+    OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myCompositAlerts.get())
+  }
+  if (!myAttribute.IsNull())
+  {
+    OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myAttribute.get())
+  }
+}
diff --git a/src/Message/Message_AlertExtended.hxx b/src/Message/Message_AlertExtended.hxx
new file mode 100644 (file)
index 0000000..add47b7
--- /dev/null
@@ -0,0 +1,88 @@
+// 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 <Message_Alert.hxx>
+#include <Message_Gravity.hxx>
+#include <TCollection_AsciiString.hxx>
+
+class Message_Attribute;
+class Message_Report;
+
+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:
+  //! 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
+  Standard_EXPORT static Handle(Message_Alert) AddAlert (const Handle(Message_Report)& theReport,
+                                                         const Handle(Message_Attribute)& theAttribute,
+                                                         const Message_Gravity theGravity);
+
+public:
+  //! Empty constructor
+  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;
+
+  //! Returns container of the alert attributes
+  const Handle(Message_Attribute)& Attribute() const { return myAttribute; }
+
+  //! Sets container of the alert attributes
+  //! @param theAttributes an attribute values
+  void SetAttribute (const Handle(Message_Attribute)& theAttribute) { myAttribute = theAttribute; }
+
+  //! Returns class provided hierarchy of alerts if created or create if the parameter is true
+  //! @param theToCreate 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.
+  Standard_EXPORT virtual Standard_Boolean SupportsMerge() const Standard_OVERRIDE;
+
+  //! If possible, merge data contained in this alert to theTarget.
+  //! Base implementation always returns false.
+  //! @return True if merged
+  Standard_EXPORT virtual Standard_Boolean Merge (const Handle(Message_Alert)& theTarget) Standard_OVERRIDE;
+
+  //! Dumps the content of me into the stream
+  virtual Standard_EXPORT void DumpJson (Standard_OStream& theOStream,
+                                         Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+
+  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
+};
+
+DEFINE_STANDARD_HANDLE(Message_AlertExtended, Message_Alert)
+
+#endif // _Message_Alert_HeaderFile
diff --git a/src/Message/Message_Attribute.cxx b/src/Message/Message_Attribute.cxx
new file mode 100644 (file)
index 0000000..3763165
--- /dev/null
@@ -0,0 +1,47 @@
+// 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 <Message_Attribute.hxx>
+
+#include <Standard_Assert.hxx>
+#include <Standard_Dump.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_Attribute, Standard_Transient)
+
+//=======================================================================
+//function : Constructor
+//purpose  :
+//=======================================================================
+Message_Attribute::Message_Attribute (const TCollection_AsciiString& theName)
+: myName (theName)
+{
+}
+
+//=======================================================================
+//function : GetMessageKey
+//purpose  :
+//=======================================================================
+Standard_CString Message_Attribute::GetMessageKey() const
+{
+  return !myName.IsEmpty() ? myName.ToCString() : "";
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_Attribute::DumpJson (Standard_OStream& theOStream, Standard_Integer) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+  OCCT_DUMP_FIELD_VALUE_STRING (theOStream, myName)
+}
diff --git a/src/Message/Message_Attribute.hxx b/src/Message/Message_Attribute.hxx
new file mode 100644 (file)
index 0000000..e1c2aaa
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 <Standard_Transient.hxx>
+#include <TCollection_AsciiString.hxx>
+
+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
+{
+  DEFINE_STANDARD_RTTIEXT(Message_Attribute, Standard_Transient)
+public:
+  //! Empty constructor
+  Standard_EXPORT Message_Attribute (const TCollection_AsciiString& theName = TCollection_AsciiString());
+
+  //! 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;
+
+  //! 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; }
+
+  //! Dumps the content of me into the stream
+  virtual Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
+
+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 (file)
index 0000000..d37cc8b
--- /dev/null
@@ -0,0 +1,256 @@
+// 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 <Message_AttributeMeter.hxx>
+
+#include <Message_AlertExtended.hxx>
+#include <Message.hxx>
+#include <Message_Report.hxx>
+#include <OSD_Chronometer.hxx>
+
+#include <Precision.hxx>
+#include <Standard_Dump.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeMeter, Message_Attribute)
+
+//=======================================================================
+//function : Constructor
+//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.Contains (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 (StartToStopValue* aValPtr = myMetrics.ChangeSeek (theMetric))
+  {
+    aValPtr->first = theValue;
+  }
+  else
+  {
+    myMetrics.Add (theMetric, std::make_pair (theValue, UndefinedMetricValue()));
+  }
+}
+
+//=======================================================================
+//function : StopValue
+//purpose  :
+//=======================================================================
+Standard_Real Message_AttributeMeter::StopValue (const Message_MetricType& theMetric) const
+{
+  if (!HasMetric (theMetric))
+  {
+    return UndefinedMetricValue();
+  }
+  return myMetrics.Seek (theMetric)->second;
+}
+
+//=======================================================================
+//function : SetStopValue
+//purpose  :
+//=======================================================================
+void Message_AttributeMeter::SetStopValue (const Message_MetricType& theMetric, const Standard_Real theValue)
+{
+  if (StartToStopValue* aValPtr = myMetrics.ChangeSeek (theMetric))
+  {
+    aValPtr->second = theValue;
+  }
+}
+
+//=======================================================================
+//function : SetAlertMetrics
+//purpose  :
+//=======================================================================
+void Message_AttributeMeter::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_IndexedMap<Message_MetricType>& anActiveMetrics = aReport->ActiveMetrics();
+
+  // time metrics
+  if (anActiveMetrics.Contains (Message_MetricType_ProcessCPUUserTime) ||
+      anActiveMetrics.Contains (Message_MetricType_ProcessCPUSystemTime) ||
+      anActiveMetrics.Contains (Message_MetricType_ThreadCPUUserTime) ||
+      anActiveMetrics.Contains (Message_MetricType_ThreadCPUSystemTime))
+  {
+    if (anActiveMetrics.Contains (Message_MetricType_ProcessCPUUserTime) ||
+        anActiveMetrics.Contains (Message_MetricType_ProcessCPUSystemTime))
+    {
+      Standard_Real aProcessUserTime, aProcessSystemTime;
+      OSD_Chronometer::GetProcessCPU (aProcessUserTime, aProcessSystemTime);
+      if (anActiveMetrics.Contains (Message_MetricType_ProcessCPUUserTime))
+      {
+        if (theStartValue)
+        {
+          aMeterAttribute->SetStartValue (Message_MetricType_ProcessCPUUserTime, aProcessUserTime);
+        }
+        else
+        {
+          aMeterAttribute->SetStopValue (Message_MetricType_ProcessCPUUserTime, aProcessUserTime);
+        }
+      }
+      if (anActiveMetrics.Contains (Message_MetricType_ProcessCPUSystemTime))
+      {
+        if (theStartValue)
+        {
+          aMeterAttribute->SetStartValue (Message_MetricType_ProcessCPUSystemTime, aProcessSystemTime);
+        }
+        else
+        {
+          aMeterAttribute->SetStopValue (Message_MetricType_ProcessCPUSystemTime, aProcessSystemTime);
+        }
+      }
+    }
+    if (anActiveMetrics.Contains (Message_MetricType_ThreadCPUUserTime) ||
+        anActiveMetrics.Contains (Message_MetricType_ThreadCPUSystemTime))
+    {
+      Standard_Real aThreadUserTime, aThreadSystemTime;
+      OSD_Chronometer::GetThreadCPU (aThreadUserTime, aThreadSystemTime);
+      if (anActiveMetrics.Contains (Message_MetricType_ThreadCPUUserTime))
+      {
+        if (theStartValue)
+        {
+          aMeterAttribute->SetStartValue (Message_MetricType_ThreadCPUUserTime, aThreadUserTime);
+        }
+        else
+        {
+          aMeterAttribute->SetStopValue (Message_MetricType_ThreadCPUUserTime, aThreadUserTime);
+        }
+      }
+      if (anActiveMetrics.Contains (Message_MetricType_ThreadCPUSystemTime))
+      {
+        if (theStartValue)
+        {
+          aMeterAttribute->SetStartValue (Message_MetricType_ThreadCPUSystemTime, aThreadSystemTime);
+        }
+        else
+        {
+          aMeterAttribute->SetStopValue (Message_MetricType_ThreadCPUSystemTime, aThreadSystemTime);
+        }
+      }
+    }
+  }
+
+  // memory metrics
+  OSD_MemInfo aMemInfo (Standard_False);
+  aMemInfo.SetActive (Standard_False);
+  NCollection_IndexedMap<OSD_MemInfo::Counter> aCounters;
+  for (NCollection_IndexedMap<Message_MetricType>::Iterator anIterator (anActiveMetrics); anIterator.More(); anIterator.Next())
+  {
+    OSD_MemInfo::Counter anInfoCounter;
+    if (!Message::ToOSDMetric (anIterator.Value(), anInfoCounter))
+    {
+      continue;
+    }
+
+    aCounters.Add (anInfoCounter);
+    aMemInfo.SetActive (anInfoCounter, Standard_True);
+  }
+  if (aCounters.IsEmpty())
+  {
+    return;
+  }
+
+  aMemInfo.Update();
+  Message_MetricType aMetricType;
+  for (NCollection_IndexedMap<OSD_MemInfo::Counter>::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()));
+    }
+  }
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_AttributeMeter::DumpJson (Standard_OStream& theOStream,
+                                       Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+  OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Message_Attribute)
+
+  for (NCollection_IndexedDataMap<Message_MetricType, StartToStopValue>::Iterator anIterator (myMetrics);
+       anIterator.More(); anIterator.Next())
+  {
+    Message_MetricType aMetricType = anIterator.Key();
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aMetricType)
+
+    Standard_Real aStartValue = anIterator.Value().first;
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aStartValue)
+
+    Standard_Real aStopValue = anIterator.Value().second;
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aStopValue)
+  }
+}
diff --git a/src/Message/Message_AttributeMeter.hxx b/src/Message/Message_AttributeMeter.hxx
new file mode 100644 (file)
index 0000000..222b6b1
--- /dev/null
@@ -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.
+
+#ifndef _Message_AttributeMeter_HeaderFile
+#define _Message_AttributeMeter_HeaderFile
+
+#include <Message_Attribute.hxx>
+#include <Message_MetricType.hxx>
+
+#include <NCollection_IndexedDataMap.hxx>
+
+class Message_Alert;
+class Message_AlertExtended;
+
+//! 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);
+
+public:
+
+  //! Sets start values of default report metrics into the alert
+  //! @param theAlert an alert  
+  static 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  
+  static void StopAlert (const Handle(Message_AlertExtended)& theAlert) { SetAlertMetrics (theAlert, Standard_False); }
+
+  //! 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
+  static Standard_EXPORT void SetAlertMetrics (const Handle(Message_AlertExtended)& theAlert,
+                                               const Standard_Boolean theStartValue);
+
+  //! Dumps the content of me into the stream
+  virtual Standard_EXPORT void DumpJson (Standard_OStream& theOStream,
+                                         Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+
+  DEFINE_STANDARD_RTTIEXT(Message_AttributeMeter, Message_Attribute)
+
+private:
+
+  typedef std::pair<Standard_Real, Standard_Real> StartToStopValue;
+  NCollection_IndexedDataMap<Message_MetricType, StartToStopValue> myMetrics; //!< computed metrics
+};
+
+#endif // _Message_AttributeMeter_HeaderFile
diff --git a/src/Message/Message_AttributeObject.cxx b/src/Message/Message_AttributeObject.cxx
new file mode 100644 (file)
index 0000000..db16d96
--- /dev/null
@@ -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 <Message_AttributeObject.hxx>
+#include <Standard_Dump.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeObject, Message_Attribute)
+
+//=======================================================================
+//function : Constructor
+//purpose  :
+//=======================================================================
+Message_AttributeObject::Message_AttributeObject (const Handle(Standard_Transient)& theObject,
+                                                  const TCollection_AsciiString& theName)
+: Message_Attribute(theName)
+{
+  myObject = theObject;
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_AttributeObject::DumpJson (Standard_OStream& theOStream,
+                                        Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+  OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Message_Attribute)
+
+  OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myObject.get())
+}
diff --git a/src/Message/Message_AttributeObject.hxx b/src/Message/Message_AttributeObject.hxx
new file mode 100644 (file)
index 0000000..1201d9e
--- /dev/null
@@ -0,0 +1,46 @@
+// 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 <Message_Attribute.hxx>
+
+class Standard_Transient;
+
+//! Alert object storing a transient object
+class Message_AttributeObject : public Message_Attribute
+{
+  DEFINE_STANDARD_RTTIEXT(Message_AttributeObject, Message_Attribute)
+public:
+  //! Constructor with string argument
+  Standard_EXPORT Message_AttributeObject (const Handle(Standard_Transient)& theObject,
+                                           const TCollection_AsciiString& theName = TCollection_AsciiString());
+
+  //! Returns object
+  //! @return the object instance
+  const Handle(Standard_Transient)& Object() const { return myObject; }
+
+  //! Sets the object
+  //! @param theObject an instance
+  void SetObject (const Handle(Standard_Transient)& theObject) { myObject = theObject; }
+
+  //! Dumps the content of me into the stream
+  virtual Standard_EXPORT void DumpJson (Standard_OStream& theOStream,
+                                         Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+
+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 (file)
index 0000000..ba0ff7e
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 <Message_AttributeStream.hxx>
+#include <Standard_Dump.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Message_AttributeStream, Message_Attribute)
+
+//=======================================================================
+//function : Constructor
+//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 ("");
+  myStream << theStream.str().c_str();
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_AttributeStream::DumpJson (Standard_OStream& theOStream,
+                                        Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+  OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Message_Attribute)
+
+  TCollection_AsciiString aStream = Standard_Dump::Text (myStream);
+  OCCT_DUMP_FIELD_VALUE_STRING (theOStream, aStream)
+}
diff --git a/src/Message/Message_AttributeStream.hxx b/src/Message/Message_AttributeStream.hxx
new file mode 100644 (file)
index 0000000..1a5ef9b
--- /dev/null
@@ -0,0 +1,45 @@
+// 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 <Message_Attribute.hxx>
+
+#include <Standard_SStream.hxx>
+
+//! Alert object storing stream value
+class Message_AttributeStream : public Message_Attribute
+{
+  DEFINE_STANDARD_RTTIEXT(Message_AttributeStream, 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);
+
+  //! Dumps the content of me into the stream
+  virtual Standard_EXPORT void DumpJson (Standard_OStream& theOStream,
+                                         Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+
+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 (file)
index 0000000..312b059
--- /dev/null
@@ -0,0 +1,183 @@
+// 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 <Message_CompositeAlerts.hxx>
+
+#include <Message_AlertExtended.hxx>
+#include <Standard_Assert.hxx>
+#include <Standard_Dump.hxx>
+
+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();
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_CompositeAlerts::DumpJson (Standard_OStream& theOStream,
+                                        Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+
+  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
+  {
+    Message_Gravity aGravity = (Message_Gravity)i;
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, aGravity)
+
+    for (Message_ListOfAlert::Iterator anIt (myAlerts[i]); anIt.More(); anIt.Next())
+    {
+      const Handle(Message_Alert)& anAlert = anIt.Value();
+      OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, anAlert.get())
+    }
+  }
+}
diff --git a/src/Message/Message_CompositeAlerts.hxx b/src/Message/Message_CompositeAlerts.hxx
new file mode 100644 (file)
index 0000000..465ad9f
--- /dev/null
@@ -0,0 +1,81 @@
+// 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 <Message_Alert.hxx>
+#include <Message_Gravity.hxx>
+#include <Message_ListOfAlert.hxx>
+#include <Standard_Transient.hxx>
+
+//! Class providing container of alerts
+class Message_CompositeAlerts : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(Message_CompositeAlerts, Standard_Transient)
+public:
+  //! Empty constructor
+  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);
+
+  //! Dumps the content of me into the stream
+  Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
+
+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
+};
+
+DEFINE_STANDARD_HANDLE(Message_CompositeAlerts, Standard_Transient)
+
+#endif // _Message_CompositeAlerts_HeaderFile
diff --git a/src/Message/Message_Level.cxx b/src/Message/Message_Level.cxx
new file mode 100644 (file)
index 0000000..caa8b5c
--- /dev/null
@@ -0,0 +1,110 @@
+// 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 <Message_Level.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_CompositeAlerts.hxx>
+#include <Message_AttributeMeter.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_Report.hxx>
+
+#include <OSD_Chronometer.hxx>
+#include <OSD_MemInfo.hxx>
+
+//=======================================================================
+//function : Constructor
+//purpose  :
+//=======================================================================
+Message_Level::Message_Level (const TCollection_AsciiString& theName)
+{
+  const Handle(Message_Report)& aDefaultReport = Message::DefaultReport();
+  if (!aDefaultReport.IsNull() && aDefaultReport->IsActiveInMessenger())
+  {
+    aDefaultReport->AddLevel (this, theName);
+  }
+}
+
+//=======================================================================
+//function : Destructor
+//purpose  :
+//=======================================================================
+Message_Level::~Message_Level()
+{
+  remove();
+}
+
+//=======================================================================
+//function : SetRootAlert
+//purpose  :
+//=======================================================================
+void Message_Level::SetRootAlert (const Handle(Message_AlertExtended)& theAlert,
+                                  const Standard_Boolean isRequiredToStart)
+{
+  myRootAlert = theAlert;
+  if (isRequiredToStart)
+  {
+    Message_AttributeMeter::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;
+  }
+
+  // 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
+  Message_AttributeMeter::StopAlert (myLastAlert);
+
+  myLastAlert = anAlertExtended;
+  // set start metrics of the new alert
+  Message_AttributeMeter::StartAlert (myLastAlert);
+
+  // 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;
+  }
+
+  Message_AttributeMeter::StopAlert (myLastAlert);
+
+  if (!Message::DefaultReport().IsNull())
+  {
+    Message::DefaultReport()->RemoveLevel (this);
+  }
+}
diff --git a/src/Message/Message_Level.hxx b/src/Message/Message_Level.hxx
new file mode 100644 (file)
index 0000000..4e14d8f
--- /dev/null
@@ -0,0 +1,80 @@
+// 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 <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_Gravity.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_MetricType.hxx>
+
+#include <NCollection_DataMap.hxx>
+#include <Standard.hxx>
+
+//! 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 attribute: 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 inside it.
+//! Levels using should be only through using OCCT_ADD_MESSAGE_LEVEL_SENTRY only. No other code is required outside.
+class Message_Level
+{
+public:
+  //! Constructor.
+  //! 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 (const TCollection_AsciiString& theName = TCollection_AsciiString());
+
+  //! 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,
+                                     const Standard_Boolean isRequiredToStart);
+
+  //! Adds new alert on the level. Stops the last alert metric, appends the alert and starts the alert metrics collecting.
+  //! Sets root alert beforehand 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);
+
+private:
+  //! Remove the current level from the report. It stops metric collecting for the last and the root alerts.
+  Standard_EXPORT void remove();
+
+private:
+  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 OCCT_ADD_MESSAGE_LEVEL_SENTRY(theMessage) \
+  Message_Level aLevel(theMessage);
+
+#endif // _Message_Level_HeaderFile
index e620ee29fc3483f0317d3b98934c97b9e326ee6c..29a57330e1b76e7ae764bd7c19db3fdb92a1fd5d 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <Message_Printer.hxx>
 #include <Message_PrinterOStream.hxx>
+#include <Standard_Dump.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Message_Messenger,Standard_Transient)
 
@@ -125,9 +126,25 @@ void Message_Messenger::Send (const Standard_CString theString,
 
 //=======================================================================
 //function : Send
-//purpose  : 
+//purpose  :
 //=======================================================================
+void Message_Messenger::Send (const Standard_SStream& theStream,
+                              const Message_Gravity theGravity) const
+{
+  for (Message_SequenceOfPrinters::Iterator aPrinterIter (myPrinters); aPrinterIter.More(); aPrinterIter.Next())
+  {
+    const Handle(Message_Printer)& aPrinter = aPrinterIter.Value();
+    if (!aPrinter.IsNull())
+    {
+      aPrinter->SendStringStream (theStream, theGravity);
+    }
+  }
+}
 
+//=======================================================================
+//function : Send
+//purpose  :
+//=======================================================================
 void Message_Messenger::Send (const TCollection_AsciiString& theString,
                               const Message_Gravity theGravity) const
 {
@@ -158,3 +175,31 @@ void Message_Messenger::Send (const TCollection_ExtendedString& theString,
     }
   }
 }
+
+//=======================================================================
+//function : Send
+//purpose  :
+//=======================================================================
+void Message_Messenger::Send (const Handle(Standard_Transient)& theObject,
+                              const Message_Gravity theGravity) const
+{
+  for (Message_SequenceOfPrinters::Iterator aPrinterIter (myPrinters); aPrinterIter.More(); aPrinterIter.Next())
+  {
+    const Handle(Message_Printer)& aPrinter = aPrinterIter.Value();
+    if (!aPrinter.IsNull())
+    {
+      aPrinter->SendObject (theObject, theGravity);
+    }
+  }
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_Messenger::DumpJson (Standard_OStream& theOStream, Standard_Integer) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPrinters.Size())
+}
index ca993d51e30809667e802da2939319edc8eb6d2e..a804a6c527756a22cb9b10cb168199ccea6eb2dc 100644 (file)
@@ -76,7 +76,7 @@ public:
       {
         if (myMessenger)
         {
-          myMessenger->Send(myStream.str().c_str(), myGravity);
+          myMessenger->Send(myStream, myGravity);
         }
         myStream.str(std::string()); // empty the buffer for possible reuse
       }
@@ -177,6 +177,10 @@ public:
   Standard_EXPORT void Send (const Standard_CString theString,
                              const Message_Gravity theGravity = Message_Warning) const;
   
+  //! See above
+  Standard_EXPORT void Send (const Standard_SStream& theStream,
+                             const Message_Gravity theGravity = Message_Warning) const;
+
   //! See above
   Standard_EXPORT void Send (const TCollection_AsciiString& theString,
                              const Message_Gravity theGravity = Message_Warning) const;
@@ -188,6 +192,9 @@ public:
   //! Create string buffer for message of specified type
   StreamBuffer Send (Message_Gravity theGravity) { return StreamBuffer (this, theGravity); }
 
+  //! See above
+  Standard_EXPORT void Send (const Handle(Standard_Transient)& theObject, const Message_Gravity theGravity = Message_Warning) const;
+
   //! Create string buffer for sending Fail message
   StreamBuffer SendFail () { return Send (Message_Fail); }
 
@@ -218,6 +225,9 @@ public:
   //! Short-cut to Send (theMessage, Message_Trace)
   void SendTrace (const TCollection_AsciiString& theMessage) { Send (theMessage, Message_Trace); }
 
+  //! Dumps the content of me into the stream
+  Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
+
 private:
 
   Message_SequenceOfPrinters myPrinters;
diff --git a/src/Message/Message_MetricType.hxx b/src/Message/Message_MetricType.hxx
new file mode 100644 (file)
index 0000000..89a1ac4
--- /dev/null
@@ -0,0 +1,34 @@
+// 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_ThreadCPUUserTime,    //!< OSD_Chronometer::GetThreadCPU user time
+  Message_MetricType_ThreadCPUSystemTime,  //!< OSD_Chronometer::GetThreadCPU system time
+  Message_MetricType_ProcessCPUUserTime,   //!< OSD_Chronometer::GetProcessCPU user time
+  Message_MetricType_ProcessCPUSystemTime, //!< OSD_Chronometer::GetProcessCPU system time
+  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
index 06a64c05d2bb97e4c6c4009575ec742204fe0941..0ac21a5dae5ae5c4869fa4a3ae0ca0da63214056 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <Message_Printer.hxx>
 
+#include <Standard_Dump.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_ExtendedString.hxx>
 
@@ -67,3 +68,31 @@ void Message_Printer::Send (const TCollection_AsciiString& theString,
     send (theString, theGravity);
   }
 }
+
+//=======================================================================
+//function : SendStringStream
+//purpose  :
+//=======================================================================
+void Message_Printer::SendStringStream (const Standard_SStream& theStream,
+                                        const Message_Gravity   theGravity) const
+{
+  if (theGravity >= myTraceLevel)
+  {
+    send (theStream.str().c_str(), theGravity);
+  }
+}
+
+//=======================================================================
+//function : SendObject
+//purpose  :
+//=======================================================================
+void Message_Printer::SendObject (const Handle(Standard_Transient)& theObject,
+                                  const Message_Gravity          theGravity) const
+{
+  if (!theObject.IsNull()
+    && theGravity >= myTraceLevel)
+  {
+    send (TCollection_AsciiString (theObject->DynamicType()->Name())
+        + ": " + Standard_Dump::GetPointerInfo (theObject), theGravity);
+  }
+}
index cd28dcee1daa575c2acbfa679dafeea410a7cc06..eceed06e0fb574fbaa2130cb56bf88f434b812c3 100644 (file)
@@ -23,6 +23,8 @@
 #include <Standard_Transient.hxx>
 #include <Standard_Boolean.hxx>
 #include <Standard_CString.hxx>
+#include <Standard_SStream.hxx>
+
 class TCollection_ExtendedString;
 class TCollection_AsciiString;
 
@@ -65,13 +67,23 @@ public:
   Standard_EXPORT virtual void Send (const TCollection_AsciiString& theString,
                                      const Message_Gravity theGravity) const;
 
+  //! Send a string message with specified trace level.
+  //! Stream is converted to string value.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void SendStringStream (const Standard_SStream& theStream, const Message_Gravity theGravity) const;
+
+  //! Send a string message with specified trace level.
+  //! The object is converted to string in format: <object kind> : <object pointer>.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void SendObject (const Handle(Standard_Transient)& theObject, const Message_Gravity theGravity) const;
+
 protected:
 
   //! Empty constructor with Message_Info trace level
   Standard_EXPORT Message_Printer();
 
   //! Send a string message with specified trace level.
-  //! This method must be redefined in descentant.
+  //! This method must be redefined in descendant.
   Standard_EXPORT virtual void send (const TCollection_AsciiString& theString,
                                      const Message_Gravity theGravity) const = 0;
 
diff --git a/src/Message/Message_PrinterToReport.cxx b/src/Message/Message_PrinterToReport.cxx
new file mode 100644 (file)
index 0000000..b59c4a1
--- /dev/null
@@ -0,0 +1,120 @@
+// 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 <Message_PrinterToReport.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_Attribute.hxx>
+#include <Message_AttributeMeter.hxx>
+#include <Message_AttributeObject.hxx>
+#include <Message_AttributeStream.hxx>
+#include <Message_Report.hxx>
+
+#include <Standard_Dump.hxx>
+#include <TCollection_ExtendedString.hxx>
+
+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 : SendStringStream
+//purpose  :
+//=======================================================================
+void Message_PrinterToReport::SendStringStream (const Standard_SStream& theStream,
+                                                const Message_Gravity   theGravity) const
+{
+  const Handle(Message_Report)& aReport = Report();
+  if (!aReport->ActiveMetrics().IsEmpty())
+  {
+    sendMetricAlert (theStream.str().c_str(), theGravity);
+    return;
+  }
+  if (Standard_Dump::HasChildKey(Standard_Dump::Text (theStream)))
+  {
+    Message_AlertExtended::AddAlert (aReport, new Message_AttributeStream (theStream, myName), theGravity);
+    myName.Clear();
+  }
+  else
+  {
+    if (!myName.IsEmpty())
+    {
+      TCollection_AsciiString aName = myName;
+      myName.Clear();
+      send (aName, theGravity);
+    }
+    myName = Standard_Dump::Text (theStream);
+  }
+}
+
+//=======================================================================
+//function : SendObject
+//purpose  :
+//=======================================================================
+void Message_PrinterToReport::SendObject (const Handle(Standard_Transient)& theObject,
+                                          const Message_Gravity theGravity) const
+{
+  const Handle(Message_Report)& aReport = Report();
+  if (!aReport->ActiveMetrics().IsEmpty())
+  {
+    sendMetricAlert (myName, theGravity);
+    return;
+  }
+
+  Message_AlertExtended::AddAlert (aReport, new Message_AttributeObject (theObject, myName), theGravity);
+}
+
+//=======================================================================
+//function : send
+//purpose  :
+//=======================================================================
+void Message_PrinterToReport::send (const TCollection_AsciiString& theString,
+                                    const Message_Gravity theGravity) const
+{
+  if (!myName.IsEmpty())
+  {
+    send (myName, theGravity);
+    myName.Clear();
+  }
+
+  const Handle(Message_Report)& aReport = Report();
+  if (!aReport->ActiveMetrics().IsEmpty())
+  {
+    sendMetricAlert (theString, theGravity);
+    return;
+  }
+  Message_AlertExtended::AddAlert (aReport, new Message_Attribute (theString), theGravity);
+}
+
+//=======================================================================
+//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);
+}
diff --git a/src/Message/Message_PrinterToReport.hxx b/src/Message/Message_PrinterToReport.hxx
new file mode 100644 (file)
index 0000000..4004b40
--- /dev/null
@@ -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_PrinterToReport_HeaderFile
+#define _Message_PrinterToReport_HeaderFile
+
+#include <Message_Printer.hxx>
+#include <Standard_Address.hxx>
+#include <Standard_OStream.hxx>
+#include <TCollection_AsciiString.hxx>
+
+class Message_Report;
+
+//! 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() {}
+
+  //! Destructor
+  virtual ~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
+  void SetReport (const Handle(Message_Report)& theReport) { myReport = theReport; }
+
+  //! Send a string message with specified trace level.
+  //! Stream is converted to string value.
+  //! Default implementation calls first method Send().
+  Standard_EXPORT virtual void SendStringStream (const Standard_SStream& theStream,
+                                                 const Message_Gravity theGravity) const Standard_OVERRIDE;
+
+  //! Send a string message with specified trace level.
+  //! The object is converted to string in format: <object kind> : <object pointer>.
+  //! 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 SendObject (const Handle(Standard_Transient)& theObject,
+                                           const Message_Gravity theGravity) const Standard_OVERRIDE;
+
+protected:
+
+  //! Send a string message with specified trace level.
+  //! This method must be redefined in descendant.
+  Standard_EXPORT virtual void send (const TCollection_AsciiString& theString,
+                                     const Message_Gravity theGravity) const Standard_OVERRIDE;
+
+  //! Send an alert with metrics active in the current report
+  Standard_EXPORT void sendMetricAlert (const TCollection_AsciiString theValue,
+                                        const Message_Gravity theGravity) const;
+
+private:
+  mutable TCollection_AsciiString myName;
+  Handle(Message_Report) myReport; //!< the report for sending alerts
+};
+
+DEFINE_STANDARD_HANDLE(Message_PrinterToReport, Message_Printer)
+
+#endif // _Message_PrinterToReport_HeaderFile
index ce3708ce51fe4f33a011482d740e438542ec85d1..2a0c458367231a913a6df67268a7ce7402c59972 100644 (file)
 // commercial license or contractual agreement.
 
 #include <Message_Report.hxx>
+
+#include <Message.hxx>
+#include <Message_AlertExtended.hxx>
+#include <Message_AttributeMeter.hxx>
+#include <Message_Attribute.hxx>
+#include <Message_CompositeAlerts.hxx>
 #include <Message_Msg.hxx>
 #include <Message_Messenger.hxx>
-#include <NCollection_Map.hxx>
+#include <Message_PrinterToReport.hxx>
+
+#include <Precision.hxx>
+#include <Standard_Dump.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Message_Report,Standard_Transient)
 
@@ -26,6 +35,8 @@ IMPLEMENT_STANDARD_RTTIEXT(Message_Report,Standard_Transient)
 //=======================================================================
 
 Message_Report::Message_Report ()
+: myLimit (-1),
+  myIsActiveInMessenger (Standard_False)
 {
 }
 
@@ -36,28 +47,28 @@ 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, the new alert will be placed below the root
+  myAlertLevels.Last()->AddAlert (theGravity, theAlert);
 }
 
 //=======================================================================
@@ -68,9 +79,11 @@ 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);
 }
 
 //=======================================================================
@@ -95,26 +108,131 @@ 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())
   {
-    if (anIt.Value()->IsInstance(theType))
-      return Standard_True;
+    return Standard_False;
   }
-  return Standard_False;
+
+  return compositeAlerts()->HasAlert (theType, theGravity);
 }
 
 //=======================================================================
-//function : Clear
+//function : IsActiveInMessenger
+//purpose  :
+//=======================================================================
+Standard_Boolean Message_Report::IsActiveInMessenger (const Handle(Message_Messenger)&) const
+{
+  return myIsActiveInMessenger;
+}
+
+//=======================================================================
+//function : ActivateInMessenger
+//purpose  :
+//=======================================================================
+void Message_Report::ActivateInMessenger (const Standard_Boolean toActivate,
+                                          const Handle(Message_Messenger)& theMessenger)
+{
+  if (toActivate == IsActiveInMessenger())
+    return;
+
+  myIsActiveInMessenger = toActivate;
+  Handle(Message_Messenger) aMessenger = theMessenger.IsNull() ? Message::DefaultMessenger() : theMessenger;
+  if (toActivate)
+  {
+    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 : UpdateActiveInMessenger
+//purpose  :
+//=======================================================================
+void Message_Report::UpdateActiveInMessenger (const Handle(Message_Messenger)& theMessenger)
+{
+  Handle(Message_Messenger) aMessenger = theMessenger.IsNull() ? Message::DefaultMessenger() : theMessenger;
+  for (Message_SequenceOfPrinters::Iterator anIterator (aMessenger->Printers()); anIterator.More(); anIterator.Next())
+  {
+    if (anIterator.Value()->IsKind(STANDARD_TYPE (Message_PrinterToReport)) &&
+        Handle(Message_PrinterToReport)::DownCast (anIterator.Value())->Report() == this)
+    {
+      myIsActiveInMessenger = Standard_True;
+      return;
+    }
+  }
+  myIsActiveInMessenger = Standard_False;
+}
+
+//=======================================================================
+//function : AddLevel
+//purpose  :
+//=======================================================================
+void Message_Report::AddLevel (Message_Level* theLevel, const TCollection_AsciiString& theName)
+{
+  myAlertLevels.Append (theLevel);
+
+  Handle(Message_AlertExtended) aLevelRootAlert = new Message_AlertExtended();
+
+  Handle(Message_Attribute) anAttribute;
+  if (!ActiveMetrics().IsEmpty())
+  {
+    anAttribute =  new Message_AttributeMeter (theName);
+  }
+  else
+  {
+    anAttribute = new Message_Attribute (theName);
+  }
+  aLevelRootAlert->SetAttribute (anAttribute);
+  theLevel->SetRootAlert (aLevelRootAlert, myAlertLevels.Size() == 1);
+
+  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 (Message_Info, theLevel->RootAlert());
+  }
+  if (myAlertLevels.Size() > 1) // this is the first level, so root alert should be pushed in the report composite of alerts
+  {
+    // root alert of next levels should be pushed under the previous level
+    Message_Level* aPrevLevel = myAlertLevels.Value (myAlertLevels.Size() - 1); // previous level
+    aPrevLevel->AddAlert (Message_Info, aLevelRootAlert);
+  }
+}
+
+//=======================================================================
+//function : RemoveLevel
 //purpose  :
 //=======================================================================
 
-void Message_Report::Clear ()
+void Message_Report::RemoveLevel (Message_Level* theLevel)
 {
-  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
+  for (int aLevelIndex = myAlertLevels.Size(); aLevelIndex >= 1; aLevelIndex--)
   {
-    myAlerts[i].Clear();
+    Message_Level* aLevel = myAlertLevels.Value (aLevelIndex);
+    if (myAlertLevels.Size() == 1) // the last level, the root item should be stopped
+    {
+      Message_AttributeMeter::StopAlert (aLevel->RootAlert());
+    }
+
+    myAlertLevels.Remove (aLevelIndex);
+    if (aLevel == theLevel)
+    {
+      return;
+    }
   }
 }
 
@@ -122,34 +240,66 @@ void Message_Report::Clear ()
 //function : Clear
 //purpose  :
 //=======================================================================
+void Message_Report::Clear()
+{
+  if (compositeAlerts().IsNull())
+  {
+    return;
+  }
+
+  compositeAlerts()->Clear();
+  myAlertLevels.Clear();
+}
 
+//=======================================================================
+//function : Clear
+//purpose  :
+//=======================================================================
 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();
 }
 
 //=======================================================================
 //function : Clear
 //purpose  :
 //=======================================================================
-
 void Message_Report::Clear (const Handle(Standard_Type)& theType)
 {
-  for (unsigned int i = 0; i < sizeof(myAlerts)/sizeof(myAlerts[0]); ++i)
+  if (compositeAlerts().IsNull())
   {
-    for (Message_ListOfAlert::Iterator anIt (myAlerts[i]); anIt.More(); )
-    {
-      if (anIt.Value().IsNull() || anIt.Value()->IsInstance (theType))
-      {
-        myAlerts[i].Remove (anIt);
-      }
-      else
-      {
-        anIt.More();
-      }
-    }
+    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.RemoveKey (theMetricType);
   }
 }
 
@@ -173,19 +323,17 @@ 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<Handle(Standard_Type)> aPassedAlerts;
-  for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next())
+  if (compositeAlerts().IsNull())
   {
-    if (aPassedAlerts.Add (anIt.Value()->DynamicType()))
-    {
-      Message_Msg aMsg (anIt.Value()->GetMessageKey());
-      theOS << aMsg.Original() << std::endl;
-    }
+    return;
   }
+
+  dumpMessages (theOS, theGravity, compositeAlerts());
 }
 
 //=======================================================================
@@ -195,9 +343,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 +356,12 @@ 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", );
-
-  // report each type of warning only once
-  NCollection_Map<Handle(Standard_Type)> aPassedAlerts;
-  for (Message_ListOfAlert::Iterator anIt (myAlerts[theGravity]); anIt.More(); anIt.Next())
+  if (compositeAlerts().IsNull())
   {
-    if (aPassedAlerts.Add (anIt.Value()->DynamicType()))
-    {
-      Message_Msg aMsg (anIt.Value()->GetMessageKey());
-      theMessenger->Send (aMsg, theGravity);
-    }
+    return;
   }
+
+  sendMessages (theMessenger, theGravity, compositeAlerts());
 }
 
 //=======================================================================
@@ -230,9 +371,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 +389,102 @@ void Message_Report::Merge (const Handle(Message_Report)& theOther, Message_Grav
     AddAlert (theGravity, anIt.Value());
   }
 }
+
+//=======================================================================
+//function : CompositeAlerts
+//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);
+  for (Message_ListOfAlert::Iterator anIt (anAlerts); anIt.More(); anIt.Next())
+  {
+    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);
+  for (Message_ListOfAlert::Iterator anIt (anAlerts); anIt.More(); anIt.Next())
+  {
+    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());
+  }
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void Message_Report::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+
+  if (!myCompositAlerts.IsNull())
+  {
+    OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myCompositAlerts.get())
+  }
+
+  Standard_Integer anAlertLevels = myAlertLevels.Size();
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, anAlertLevels)
+
+  for (NCollection_IndexedMap<Message_MetricType>::Iterator anIterator (myActiveMetrics); anIterator.More(); anIterator.Next())
+  {
+    Message_MetricType anActiveMetric = anIterator.Value();
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, anActiveMetric)
+  }
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLimit)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsActiveInMessenger)
+}
index beddf143a151f6c6bd5ee8af89104bf2dbb070ef..9d43de9e86e360adaa77e80dbfd3e843b7413975 100644 (file)
 #define _Message_Report_HeaderFile
 
 #include <Message_Gravity.hxx>
+#include <Message_Level.hxx>
 #include <Message_ListOfAlert.hxx>
+#include <Message_MetricType.hxx>
+#include <NCollection_IndexedMap.hxx>
+#include <NCollection_Sequence.hxx>
 #include <Standard_Mutex.hxx>
 
+class Message_CompositeAlerts;
 class Message_Messenger;
 
 class Message_Report;
+
 DEFINE_STANDARD_HANDLE(Message_Report, MMgt_TShared)
 
 //! Container for alert messages, sorted according to their gravity.
@@ -46,7 +52,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
 {
 public:
@@ -67,6 +74,28 @@ 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);
+
+  //! Updates internal flag IsActiveInMessenger.
+  //! It becomes true if messenger contains at least one instance of Message_PrinterToReport.
+  //! @param theMessenger the messenger. If it's NULL, the default messenger is used
+  Standard_EXPORT void UpdateActiveInMessenger (const Handle(Message_Messenger)& theMessenger = NULL);
+  
+  //! Add new level of alerts
+  //! @param theLevel a level 
+  Standard_EXPORT void AddLevel (Message_Level* theLevel, const TCollection_AsciiString& theName);
+
+  //! Remove level of alerts
+  Standard_EXPORT void RemoveLevel (Message_Level* theLevel);
+
   //! Clears all collected alerts
   Standard_EXPORT void Clear ();
 
@@ -76,6 +105,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_IndexedMap<Message_MetricType>& 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.
+  //! @param theLimit limit value
+  void SetLimit(const Standard_Integer theLimit) { myLimit = theLimit; }
+
   //! Dumps all collected alerts to stream
   Standard_EXPORT void Dump (Standard_OStream& theOS);
 
@@ -97,15 +145,36 @@ public:
   //! Merges alerts with specified gravity from theOther report into this
   Standard_EXPORT void Merge (const Handle(Message_Report)& theOther, Message_Gravity theGravity);
 
+  //! Dumps the content of me into the stream
+  Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
+
   // 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<Message_Level*> myAlertLevels;   //!< container of active levels, new alerts are added below the latest level
+  NCollection_IndexedMap<Message_MetricType>  myActiveMetrics; //!< metrics to compute on alerts
+
+  Standard_Integer myLimit; //!< Maximum number of collected alerts on the top level
+  Standard_Boolean myIsActiveInMessenger; //! state whether the report is activated in messenger
 };
 
 #endif // _Message_Report_HeaderFile
index 8e17f304b65771f2acf1f64edf3c142647d89c20..27345a189fc39878a902c236d20ed90e5448ba2e 100644 (file)
@@ -1,5 +1,7 @@
 TopoDS.hxx
 TopoDS.lxx
+TopoDS_AlertAttribute.hxx
+TopoDS_AlertAttribute.cxx
 TopoDS_Builder.cxx
 TopoDS_Builder.hxx
 TopoDS_Builder.lxx
diff --git a/src/TopoDS/TopoDS_AlertAttribute.cxx b/src/TopoDS/TopoDS_AlertAttribute.cxx
new file mode 100644 (file)
index 0000000..f0c60d3
--- /dev/null
@@ -0,0 +1,69 @@
+// Created on: 2018-06-10
+// Created by: Natalia Ermolaeva
+// Copyright (c) 2018-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 <TopoDS_AlertAttribute.hxx>
+
+#include <Message_PrinterToReport.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(TopoDS_AlertAttribute, Message_Attribute)
+
+//=======================================================================
+//function : TopoDS_AlertAttribute
+//purpose  :
+//=======================================================================
+TopoDS_AlertAttribute::TopoDS_AlertAttribute (const TopoDS_Shape& theShape,
+                                              const TCollection_AsciiString& theName)
+: Message_AttributeStream (Standard_SStream(), theName), myShape (theShape)
+{
+  Standard_SStream aStream;
+  theShape.DumpJson (aStream);
+
+  SetStream (aStream);
+}
+
+//=======================================================================
+//function : Send
+//purpose  :
+//=======================================================================
+void TopoDS_AlertAttribute::Send (const Handle(Message_Messenger)& theMessenger,
+                                  const TopoDS_Shape& theShape)
+{
+  for (Message_SequenceOfPrinters::Iterator aPrinterIter (theMessenger->Printers()); aPrinterIter.More(); aPrinterIter.Next())
+  {
+    const Handle(Message_Printer)& aPrinter = aPrinterIter.Value();
+    if (!aPrinter->IsKind (STANDARD_TYPE (Message_PrinterToReport)))
+    {
+      continue;
+    }
+
+    Handle (Message_PrinterToReport) aPrinterToReport = Handle(Message_PrinterToReport)::DownCast (aPrinter);
+    const Handle(Message_Report)& aReport = aPrinterToReport->Report();
+
+    Message_AlertExtended::AddAlert (aReport, new TopoDS_AlertAttribute (theShape), Message_Info);
+  }
+}
+
+//=======================================================================
+//function : DumpJson
+//purpose  :
+//=======================================================================
+void TopoDS_AlertAttribute::DumpJson (Standard_OStream& theOStream,
+                                      Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+  OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Message_Attribute)
+
+  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myShape)
+}
diff --git a/src/TopoDS/TopoDS_AlertAttribute.hxx b/src/TopoDS/TopoDS_AlertAttribute.hxx
new file mode 100644 (file)
index 0000000..f6cb752
--- /dev/null
@@ -0,0 +1,61 @@
+// Created on: 2018-06-10
+// Created by: Natalia Ermolaeva
+// Copyright (c) 2018-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 _TopoDS_AlertAttribute_HeaderFile
+#define _TopoDS_AlertAttribute_HeaderFile
+
+#include <Message_AttributeStream.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <Message_Report.hxx>
+
+#include <TopoDS_Shape.hxx>
+
+class Message_Messenger;
+
+//! Alert attribute object storing TopoDS shape in its field
+class TopoDS_AlertAttribute : public Message_AttributeStream
+{
+  DEFINE_STANDARD_RTTIEXT(TopoDS_AlertAttribute, Message_AttributeStream)
+public:
+  //! Constructor with shape argument
+  Standard_EXPORT TopoDS_AlertAttribute (const TopoDS_Shape& theShape,
+                                         const TCollection_AsciiString& theName = TCollection_AsciiString());
+
+  //! Returns contained shape
+  const TopoDS_Shape& GetShape() const { return myShape; }
+
+public:
+
+  //! Push shape information into messenger
+  Standard_EXPORT static void Send (const Handle(Message_Messenger)& theMessenger,
+                                    const TopoDS_Shape& theShape);
+
+  //! Dumps the content of me into the stream
+  Standard_EXPORT void DumpJson (Standard_OStream& theOStream,
+                                 Standard_Integer theDepth = -1) const Standard_OVERRIDE;
+
+private:
+  TopoDS_Shape myShape;
+};
+
+inline const Handle(Message_Messenger)& operator<< (const Handle(Message_Messenger)& theMessenger,
+                                                    const TopoDS_Shape& theShape)
+{
+  TopoDS_AlertAttribute::Send (theMessenger, theShape);
+  return theMessenger;
+}
+
+#endif // _TopoDS_AlertAttribute_HeaderFile
diff --git a/tests/demo/draw/messenger b/tests/demo/draw/messenger
new file mode 100644 (file)
index 0000000..e42f3fe
--- /dev/null
@@ -0,0 +1,28 @@
+puts "=================================="
+puts "0029451: Information Message Alert to debug an algorithm or object functionality"
+puts "=================================="
+pload MODELING
+
+#ostream printer
+PrintMessenger
+SendMessage "processing a text message in ostream" "information message" "test faulty message" "warning message"
+
+#report printer
+SetMessagePrinter -type report
+PrintMessenger
+SendMessage "processing a text message in report" "information message" "test faulty message" "warning message"
+
+PrintReport -dumpJson
+
+#report printer with metric
+ClearReport
+SetReportMetric 1 3
+CollectMetricMessages -activate 1
+SendMessage "processing metric report"
+CollectMetricMessages -activate 0
+
+PrintReport -dumpJson
+SetMessagePrinter -type report -state off
+PrintMessenger
+
+puts "TEST COMPLETED"
\ No newline at end of file