LCOV - code coverage report
Current view: top level - artdaq/ArtModules - ArtdaqOutput.hh (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 346 0
Test Date: 2026-10-29 00:35:58 Functions: 0.0 % 101 0

            Line data    Source code
       1              : #ifndef ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQOUTPUT_HH_
       2              : #define ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQOUTPUT_HH_
       3              : 
       4              : #include "TRACE/tracemf.h"  // Pre-empt TRACE/trace.h from Fragment.hh.
       5              : #include "artdaq-core/Data/Fragment.hh"
       6              : 
       7              : #include "artdaq-core/Data/RawEvent.hh"
       8              : #include "artdaq-core/Data/detail/ParentageMap.hh"
       9              : #include "artdaq/DAQdata/Globals.hh"
      10              : #include "artdaq/DAQdata/NetMonHeader.hh"
      11              : 
      12              : #include "art/Framework/Core/OutputModule.h"
      13              : #include "art/Framework/Principal/EventPrincipal.h"
      14              : #include "art/Framework/Principal/OutputHandle.h"
      15              : #include "art/Framework/Principal/RunPrincipal.h"
      16              : #include "art/Framework/Principal/SubRunPrincipal.h"
      17              : #include "art/Persistency/Provenance/ModuleContext.h"
      18              : #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
      19              : #include "art_root_io/setup.h"
      20              : 
      21              : #include "canvas/Persistency/Common/WrappedTypeID.h"
      22              : #include "canvas/Persistency/Provenance/BranchDescription.h"
      23              : #include "canvas/Persistency/Provenance/BranchKey.h"
      24              : #include "canvas/Persistency/Provenance/ParentageRegistry.h"
      25              : #include "canvas/Persistency/Provenance/ProcessConfiguration.h"
      26              : #include "canvas/Persistency/Provenance/ProcessConfigurationID.h"
      27              : #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
      28              : #include "canvas/Persistency/Provenance/ProductList.h"
      29              : #include "canvas/Persistency/Provenance/ProductProvenance.h"
      30              : #include "canvas/Persistency/Provenance/RunAuxiliary.h"
      31              : #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
      32              : #include "canvas/Utilities/Exception.h"
      33              : #include "fhiclcpp/ParameterSet.h"
      34              : #include "fhiclcpp/ParameterSetRegistry.h"
      35              : 
      36              : #include <TBufferFile.h>
      37              : #include <TClass.h>
      38              : #include <TList.h>
      39              : #include <TStreamerInfo.h>
      40              : 
      41              : #include <unistd.h>
      42              : #include <algorithm>
      43              : #include <iomanip>
      44              : #include <iostream>
      45              : #include <iterator>
      46              : #include <memory>
      47              : #include <mutex>
      48              : #include <sstream>
      49              : #include <string>
      50              : #include <vector>
      51              : 
      52              : #define TLVL_ENTER_EXIT 33
      53              : #define TLVL_SENDINIT 39
      54              : #define TLVL_SENDINIT_VERBOSE1 40
      55              : #define TLVL_SENDINIT_VERBOSE2 41
      56              : #define TLVL_WRITEDATAPRODUCTS 42
      57              : #define TLVL_WRITEDATAPRODUCTS_VERBOSE 43
      58              : #define TLVL_WRITE 44
      59              : #define TLVL_WRITERUN 45
      60              : #define TLVL_WRITERUN_VERBOSE 46
      61              : #define TLVL_WRITESUBRUN 47
      62              : #define TLVL_WRITESUBRUN_VERBOSE 48
      63              : #define TLVL_EXTRACTPRODUCTS 49
      64              : #define TLVL_EXTRACTPRODUCTS_VERBOSE 50
      65              : #define TLVL_BEGINJOB 51
      66              : #define TLVL_BEGINJOB_VERBOSE 52
      67              : 
      68              : namespace art {
      69              : class ArtdaqOutput;
      70              : }  // namespace art
      71              : 
      72              : static artdaq::FragmentPtr outputFrag = nullptr;
      73              : static std::mutex outputFragMutex;
      74            0 : inline char* Fragment_ReAllocChar(char* dataPtr, size_t size, size_t /*oldsize*/)
      75              : {
      76            0 :         if (outputFrag != nullptr && dataPtr == reinterpret_cast<char*>(outputFrag->dataBegin()))  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
      77              :         {
      78            0 :                 outputFrag->resizeBytes(size);
      79              : 
      80            0 :                 return reinterpret_cast<char*>(outputFrag->dataBegin());  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
      81              :         }
      82            0 :         return nullptr;
      83              : }
      84              : 
      85              : /// <summary>
      86              : /// This is the base class for artdaq OutputModules, providing the serialization interface for art Events.
      87              : /// </summary>
      88              : class art::ArtdaqOutput : public art::OutputModule
      89              : {
      90              : public:
      91              :         /// <summary>
      92              :         /// ArtdaqOutput Constructor
      93              :         /// </summary>
      94              :         /// <param name="ps">ParameterSet used to configure art::OutputModule</param>
      95            0 :         explicit ArtdaqOutput(fhicl::ParameterSet const& ps)
      96            0 :             : OutputModule(ps), productList_(), raw_data_label_(ps.get<std::string>("raw_data_label", "daq"))
      97              :         {
      98            0 :                 root::setup();
      99            0 :         }
     100              : 
     101              :         /// <summary>
     102              :         /// Destructor
     103              :         /// </summary>
     104            0 :         virtual ~ArtdaqOutput() = default;
     105              : 
     106              : protected:
     107              :         /// <summary>
     108              :         /// Perform actions necessary for opening files. No-op, but derived classes may override
     109              :         /// </summary>
     110            0 :         virtual void openFile(FileBlock const&)
     111              :         {
     112            0 :                 TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin/End: ArtdaqOutput::openFile(const FileBlock&)";
     113            0 :         }
     114              : 
     115              :         /// <summary>
     116              :         /// Perform actions necessary for closing files. No-op, but derived classes may override
     117              :         /// </summary>
     118            0 :         virtual void closeFile() { TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin/End: ArtdaqOutput::closeFile()"; }
     119              : 
     120              :         /// <summary>
     121              :         /// Perform actions necessary after closing the input file. No-op, but derived classes may override
     122              :         /// </summary>
     123            0 :         virtual void respondToCloseInputFile(FileBlock const&)
     124              :         {
     125            0 :                 TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin/End: ArtdaqOutput::"
     126            0 :                                                          "respondToCloseOutputFiles(FileBlock const&)";
     127            0 :         }
     128              : 
     129              :         /// <summary>
     130              :         /// Perform actions necessary after closing the output file(s). No-op, but derived classes may override
     131              :         /// </summary>
     132            0 :         virtual void respondToCloseOutputFiles(FileBlock const&)
     133              :         {
     134            0 :                 TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin/End: ArtdaqOutput::"
     135            0 :                                                          "respondToCloseOutputFiles(FileBlock const&)";
     136            0 :         }
     137              : 
     138              :         virtual void beginJob();
     139              : 
     140              :         /// <summary>
     141              :         /// Perform End-of-Job actions. No-op, but derived classes may override
     142              :         /// </summary>
     143            0 :         virtual void endJob()
     144              :         {
     145            0 :                 TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin/End: ArtdaqOutput::endJob()";
     146            0 :         }
     147              : 
     148              :         /// <summary>
     149              :         /// Perform Begin Run actions. Derived classes should implement beginRun_ instead.
     150              :         /// </summary>
     151              :         /// <param name="rp">RunPrincipal of new run</param>
     152            0 :         void beginRun(RunPrincipal const& rp) final
     153              :         {
     154            0 :                 if (!initMsgSent_)
     155              :                 {
     156            0 :                         art::ProcessHistory ph = rp.processHistory();
     157            0 :                         ph.push_back(moduleDescription().processConfiguration());
     158            0 :                         art::ProcessHistoryRegistry::emplace(ph.id(), ph);
     159            0 :                         send_init_message();
     160            0 :                 }
     161            0 :                 beginRun_(rp);
     162            0 :         }
     163              :         /// <summary>
     164              :         /// Perform Begin Run actions. No-op, but derived classes may override
     165              :         /// </summary>
     166            0 :         virtual void beginRun_(RunPrincipal const&) {}
     167              : 
     168              :         /// <summary>
     169              :         /// Perform Begin SubRun actions. Derived classes should implement beginSubRun_ instead.
     170              :         /// </summary>
     171              :         /// <param name="srp">SubRunPrincipal of new subrun</param>
     172            0 :         void beginSubRun(SubRunPrincipal const& srp) final
     173              :         {
     174            0 :                 beginSubRun_(srp);
     175            0 :         }
     176              :         /// <summary>
     177              :         /// Perform Begin SubRun actions. No-op, but derived classes may override
     178              :         /// </summary>
     179            0 :         virtual void beginSubRun_(SubRunPrincipal const&) {}
     180              : 
     181              :         /// <summary>
     182              :         /// Perform actions for each event. Derived classes should implement event_ instead.
     183              :         /// </summary>
     184              :         /// <param name="ep">EventPrincipal of event</param>
     185            0 :         void event(EventPrincipal const& ep) final
     186              :         {
     187            0 :                 event_(ep);
     188            0 :         }
     189              :         /// <summary>
     190              :         /// Perform actions for each event. No-op, but derived classes may override
     191              :         /// </summary>
     192            0 :         virtual void event_(EventPrincipal const&) {}
     193              : 
     194              :         /// <summary>
     195              :         /// Write an EventPrincipal to TBufferFile and send
     196              :         /// </summary>
     197              :         /// <param name="ep">EventPrincipal to write</param>
     198              :         void write(EventPrincipal& ep) final;
     199              : 
     200              :         /// <summary>
     201              :         /// Write a RunPrincipal to TBufferFile and send
     202              :         /// </summary>
     203              :         /// <param name="rp">RunPrincipal to write</param>
     204              :         void writeRun(RunPrincipal& rp) final;
     205              : 
     206              :         /// <summary>
     207              :         /// Write a SubRunPrincipal to TBufferFile and send
     208              :         /// </summary>
     209              :         /// <param name="srp">SubRunPrincipal to write</param>
     210              :         void writeSubRun(SubRunPrincipal& srp) final;
     211              : 
     212              :         /// <summary>
     213              :         /// Extract the data products from a Principal and write them to the TBufferFile
     214              :         /// </summary>
     215              :         /// <param name="msg">Output TBufferFile</param>
     216              :         /// <param name="principal">Principal from which to extract products</param>
     217              :         /// <param name="bkv">Branch Keys for data products</param>
     218              :         void writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv);
     219              : 
     220              :         /// <summary>
     221              :         /// Send an init message downstream.
     222              :         /// </summary>
     223              :         void send_init_message();
     224              : 
     225              :         /// <summary>
     226              :         /// Send the serialized art Event downstream. Artdaq output modules should define this function.
     227              :         /// </summary>
     228              :         /// <param name="msg">Serialized art Event</param>
     229              :         virtual void SendMessage(artdaq::FragmentPtr& msg) = 0;
     230              : 
     231              : private:
     232              :         ArtdaqOutput(ArtdaqOutput const&) = delete;
     233              :         ArtdaqOutput(ArtdaqOutput&&) = delete;
     234              :         ArtdaqOutput& operator=(ArtdaqOutput const&) = delete;
     235              :         ArtdaqOutput& operator=(ArtdaqOutput&&) = delete;
     236              : 
     237              :         bool initMsgSent_{false};
     238              :         ProductList productList_;
     239              :         size_t last_fragment_size_{10};
     240              :         artdaq::Fragment::sequence_id_t last_sequence_id_{0};
     241              :         artdaq::Fragment::timestamp_t last_timestamp_{0};
     242              :         std::string raw_data_label_;
     243              : 
     244            0 :         std::unique_ptr<TBufferFile> prepareMessage(artdaq::Fragment::sequence_id_t seqID, artdaq::Fragment::timestamp_t ts, artdaq::Fragment::type_t type)
     245              :         {
     246            0 :                 artdaq::NetMonHeader hdr{};
     247            0 :                 outputFragMutex.lock();
     248            0 :                 outputFrag = std::make_unique<artdaq::Fragment>(last_fragment_size_, seqID, my_rank, type, hdr, ts);
     249            0 :                 auto msg = std::make_unique<TBufferFile>(TBuffer::kWrite, last_fragment_size_ * sizeof(artdaq::RawDataType), outputFrag->dataBegin(), kFALSE, &Fragment_ReAllocChar);
     250            0 :                 msg->SetWriteMode();
     251              : 
     252            0 :                 if (seqID > last_sequence_id_) last_sequence_id_ = seqID;
     253            0 :                 if (ts > last_timestamp_) last_timestamp_ = ts;
     254              : 
     255            0 :                 return msg;
     256            0 :         }
     257              : 
     258            0 :         void sendMessage(std::unique_ptr<TBufferFile>& msg)
     259              :         {
     260            0 :                 artdaq::NetMonHeader hdr{};
     261            0 :                 hdr.data_length = static_cast<uint64_t>(msg->Length());
     262            0 :                 outputFrag->updateMetadata(hdr);
     263            0 :                 outputFrag->resizeBytes(hdr.data_length);
     264            0 :                 last_fragment_size_ = std::ceil(msg->Length() / static_cast<double>(sizeof(artdaq::RawDataType)));
     265              : 
     266            0 :                 SendMessage(outputFrag);
     267            0 :                 outputFragMutex.unlock();
     268            0 :         }
     269              : };
     270              : 
     271            0 : inline void art::ArtdaqOutput::send_init_message()
     272              : {
     273            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin: ArtdaqOutput::send_init_message()";
     274              :         //
     275              :         //  Get the classes we will need.
     276              :         //
     277              :         // static TClass* string_class = TClass::GetClass("std::string");
     278              :         // if (string_class == nullptr) {
     279              :         //      throw art::Exception(art::errors::DictionaryNotFound) <<
     280              :         //              "ArtdaqOutput static send_init_message(): "
     281              :         //              "Could not get TClass for std::string!";
     282              :         //}
     283            0 :         static TClass* product_list_class = TClass::GetClass("std::map<art::BranchKey,art::BranchDescription>");
     284            0 :         if (product_list_class == nullptr)
     285              :         {
     286            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "  // NOLINT(cert-err60-cpp)
     287              :                                                                          "Could not get TClass for "
     288            0 :                                                                          "map<art::BranchKey,art::BranchDescription>!";
     289              :         }
     290              :         // typedef std::map<const ProcessHistoryID,ProcessHistory> ProcessHistoryMap;
     291              :         // TClass* process_history_map_class = TClass::GetClass(
     292              :         //    "std::map<const art::ProcessHistoryID,art::ProcessHistory>");
     293              :         // FIXME: Replace the "2" here with a use of the proper enum value!
     294            0 :         static TClass* process_history_map_class = TClass::GetClass("std::map<const art::Hash<2>,art::ProcessHistory>");
     295            0 :         if (process_history_map_class == nullptr)
     296              :         {
     297            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "  // NOLINT(cert-err60-cpp)
     298              :                                                                          "Could not get class for "
     299            0 :                                                                          "std::map<const art::Hash<2>,art::ProcessHistory>!";
     300              :         }
     301              :         // static TClass* parentage_map_class = TClass::GetClass(
     302              :         //    "std::map<const art::ParentageID,art::Parentage>");
     303            0 :         static TClass* parentage_map_class = TClass::GetClass("art::ParentageMap");
     304            0 :         if (parentage_map_class == nullptr)
     305              :         {
     306            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message(): "  // NOLINT(cert-err60-cpp)
     307            0 :                                                                          "Could not get class for ParentageMap.";
     308              :         }
     309            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "parentage_map_class: " << static_cast<void*>(parentage_map_class);
     310              : 
     311              :         //
     312              :         //  Construct and send the init message.
     313              :         //
     314            0 :         auto msg = prepareMessage(0, artdaq::Globals::my_art_id_, artdaq::Fragment::InitFragmentType);
     315              :         //
     316              :         //  Stream the message type code.
     317              :         //
     318            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Streaming message type code ...";
     319            0 :         msg->WriteULong(1);
     320            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Finished streaming message type code.";
     321              : 
     322              :         //
     323              :         // Stream Class info
     324              :         //
     325              :         // ELF: 6/11/2019: This is being done so that if the receiver is a newer version of art/ROOT, it can still understand our version.
     326            0 :         TList infos;
     327              :         std::vector<std::string> classNames{"std::map<art::BranchKey,art::BranchDescription>", "std::map<const art::Hash<2>,art::ProcessHistory>", "art::ParentageMap",
     328            0 :                                             "art::BranchKey", "art::ProductProvenance", "art::RunAuxiliary", "art::SubRunAuxiliary", "art::EventAuxiliary"};
     329            0 :         for (auto& className : classNames)
     330              :         {
     331            0 :                 TClass* class_ptr = TClass::GetClass(className.c_str());
     332            0 :                 if (class_ptr == nullptr)
     333              :                 {
     334            0 :                         throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::send_init_message: Could not get TClass for " << className << "!";  // NOLINT(cert-err60-cpp)
     335              :                 }
     336            0 :                 infos.Add(class_ptr->GetStreamerInfo());
     337              :         }
     338            0 :         msg->WriteObject(&infos);
     339              : 
     340              :         //
     341              :         //  Stream the ParameterSetRegistry.
     342              :         //
     343            0 :         ULong_t ps_cnt = fhicl::ParameterSetRegistry::size();
     344            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): parameter set count: " << ps_cnt;
     345            0 :         msg->WriteULong(ps_cnt);
     346            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Streaming parameter sets ...";
     347            0 :         for (auto I = std::begin(fhicl::ParameterSetRegistry::get()), E = std::end(fhicl::ParameterSetRegistry::get());
     348            0 :              I != E; ++I)
     349              :         {
     350            0 :                 TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "Pset ID " << I->first << ": " << I->second.to_string();
     351            0 :                 std::string pset_str = I->second.to_string();
     352              :                 // msg->WriteObjectAny(&pset_str, string_class);
     353            0 :                 msg->WriteStdString(pset_str);
     354            0 :         }
     355            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Finished streaming parameter sets.";
     356              : 
     357              :         //
     358              :         //  Stream the MasterProductRegistry.
     359              :         //
     360            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Streaming Product List sz=" << productList_.size() << "...";
     361            0 :         msg->WriteObjectAny(&productList_, product_list_class);
     362            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Finished streaming Product List.";
     363              : 
     364            0 :         art::ProcessHistoryMap phr;
     365            0 :         for (auto const& pr : art::ProcessHistoryRegistry::get())
     366              :         {
     367            0 :                 phr.emplace(pr);
     368              :         }
     369              :         //
     370              :         //  Dump the ProcessHistoryRegistry.
     371              :         //
     372            0 :         TLOG(TLVL_SENDINIT_VERBOSE2, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Dumping ProcessHistoryRegistry ...";
     373              :         // typedef std::map<const ProcessHistoryID,ProcessHistory>
     374              :         //    ProcessHistoryMap;
     375            0 :         TLOG(TLVL_SENDINIT_VERBOSE2, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): phr: size: " << phr.size();
     376            0 :         for (auto I = phr.begin(), E = phr.end(); I != E; ++I)
     377              :         {
     378            0 :                 std::ostringstream OS;
     379            0 :                 I->first.print(OS);
     380            0 :                 TLOG(TLVL_SENDINIT_VERBOSE2, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): phr: id: '" << OS.str() << "'";
     381            0 :         }
     382              :         //
     383              :         //  Stream the ProcessHistoryRegistry.
     384              :         //
     385            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Streaming ProcessHistoryRegistry ...";
     386              :         // typedef std::map<const ProcessHistoryID,ProcessHistory>
     387              :         //    ProcessHistoryMap;
     388            0 :         const art::ProcessHistoryMap& phm = phr;
     389            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): phm: size: " << phm.size();
     390            0 :         msg->WriteObjectAny(&phm, process_history_map_class);
     391            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Finished streaming ProcessHistoryRegistry.";
     392              : 
     393              :         //
     394              :         //  Stream the ParentageRegistry.
     395              :         //
     396            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Streaming ParentageRegistry ..." << static_cast<void*>(parentage_map_class);
     397            0 :         art::ParentageMap parentageMap{};
     398            0 :         for (auto const& pr : art::ParentageRegistry::get())
     399              :         {
     400            0 :                 parentageMap.emplace(pr.first, pr.second);
     401              :         }
     402              : 
     403            0 :         msg->WriteObjectAny(&parentageMap, parentage_map_class);
     404              : 
     405            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Finished streaming ParentageRegistry.";
     406              : 
     407            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Sending init message";
     408            0 :         sendMessage(msg);
     409            0 :         TLOG(TLVL_SENDINIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): Done sending init message, sleeping to ensure delivery";
     410            0 :         usleep(1000000);  // Sleep to allow peer init messages to be sent/received
     411            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "ArtdaqOutput::send_init_message(): END";
     412            0 :         initMsgSent_ = true;
     413            0 : }
     414              : 
     415            0 : inline void art::ArtdaqOutput::writeDataProducts(std::unique_ptr<TBufferFile>& msg, const Principal& principal, std::vector<BranchKey*>& bkv)
     416              : {
     417            0 :         TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "Begin: ArtdaqOutput::writeDataProducts(...)";
     418              :         //
     419              :         //  Fetch the class dictionaries we need for
     420              :         //  writing out the data products.
     421              :         //
     422            0 :         static TClass* branch_key_class = TClass::GetClass("art::BranchKey");
     423            0 :         if (branch_key_class == nullptr)
     424              :         {
     425            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): "  // NOLINT(cert-err60-cpp)
     426            0 :                                                                          "Could not get TClass for art::BranchKey!";
     427              :         }
     428            0 :         static TClass* prdprov_class = TClass::GetClass("art::ProductProvenance");
     429            0 :         if (prdprov_class == nullptr)
     430              :         {
     431            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeDataProducts(...): "  // NOLINT(cert-err60-cpp)
     432            0 :                                                                          "Could not get TClass for art::ProductProvenance!";
     433              :         }
     434              : 
     435              :         //
     436              :         //  Calculate the data product count.
     437              :         //
     438            0 :         ULong_t prd_cnt = 0;
     439              :         // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
     440            0 :         for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
     441              :         {
     442            0 :                 auto const& productDescription = I->second->productDescription();
     443            0 :                 auto const& refs = keptProducts()[productDescription.branchType()];
     444            0 :                 bool found = false;
     445            0 :                 for (auto const& ref : refs)
     446              :                 {
     447            0 :                         if (ref.second == productDescription)
     448              :                         {
     449            0 :                                 found = true;
     450            0 :                                 break;
     451              :                         }
     452              :                 }
     453            0 :                 if (!I->second->productAvailable() || !found)
     454              :                 {
     455            0 :                         continue;
     456              :                 }
     457            0 :                 ++prd_cnt;
     458              :         }
     459              :         //
     460              :         //  Write the data product count.
     461              :         //
     462            0 :         TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "ArtdaqOutput::writeDataProducts(...): Streaming product count: " +
     463            0 :                                                             std::to_string(prd_cnt);
     464            0 :         msg->WriteULong(prd_cnt);
     465            0 :         TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "ArtdaqOutput::writeDataProducts(...): Finished streaming product count.";
     466              : 
     467              :         //
     468              :         //  Loop over the groups in the RunPrincipal and
     469              :         //  write out the data products.
     470              :         //
     471              :         // Note: We need this vector of keys because the ROOT I/O mechanism
     472              :         //       requires that each object inserted in the message has a
     473              :         //       unique address, so we force that by holding on to each
     474              :         //       branch key manufactured in the loop until after we are
     475              :         //       done constructing the message.
     476              :         //
     477            0 :         bkv.reserve(prd_cnt);
     478              :         // std::map<art::BranchID, std::shared_ptr<art::Group>>::const_iterator
     479            0 :         for (auto I = principal.begin(), E = principal.end(); I != E; ++I)
     480              :         {
     481            0 :                 auto const& productDescription = I->second->productDescription();
     482            0 :                 auto const& refs = keptProducts()[productDescription.branchType()];
     483            0 :                 bool found = false;
     484            0 :                 for (auto const& ref : refs)
     485              :                 {
     486            0 :                         if (ref.second == productDescription)
     487              :                         {
     488            0 :                                 found = true;
     489            0 :                                 break;
     490              :                         }
     491              :                 }
     492            0 :                 if (!I->second->productAvailable() || !found)
     493              :                 {
     494            0 :                         continue;
     495              :                 }
     496            0 :                 const BranchDescription& bd(I->second->productDescription());
     497            0 :                 bkv.push_back(new BranchKey(bd));
     498            0 :                 TLOG(TLVL_WRITEDATAPRODUCTS_VERBOSE, "ArtdaqOutput")
     499            0 :                     << "ArtdaqOutput::writeDataProducts(...): Dumping branch key           of class: '"
     500            0 :                     << bkv.back()->friendlyClassName_ << "' modlbl: '" << bkv.back()->moduleLabel_ << "' instnm: '"
     501            0 :                     << bkv.back()->productInstanceName_ << "' procnm: '" << bkv.back()->processName_ << "'";
     502            0 :                 TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "ArtdaqOutput::writeDataProducts(...): "
     503            0 :                                                                 "Streaming branch key         of class: '"
     504            0 :                                                              << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
     505            0 :                                                              << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
     506            0 :                 msg->WriteObjectAny(bkv.back(), branch_key_class);
     507              : 
     508            0 :                 TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "ArtdaqOutput::writeDataProducts(...): "
     509            0 :                                                                 "Streaming product            of class: '"
     510            0 :                                                              << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
     511            0 :                                                              << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
     512              : 
     513            0 :                 OutputHandle oh = principal.getForOutput(bd.productID(), true);
     514            0 :                 const EDProduct* prd = oh.wrapper();
     515            0 :                 TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "Class for branch " << bd.wrappedName() << " is "
     516            0 :                                                              << static_cast<void*>(TClass::GetClass(bd.wrappedName().c_str()));
     517            0 :                 msg->WriteObjectAny(prd, TClass::GetClass(bd.wrappedName().c_str()));
     518            0 :                 TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "ArtdaqOutput::writeDataProducts(...): "
     519            0 :                                                                 "Streaming product provenance of class: '"
     520            0 :                                                              << bd.producedClassName() << "' modlbl: '" << bd.moduleLabel() << "' instnm: '"
     521            0 :                                                              << bd.productInstanceName() << "' procnm: '" << bd.processName() << "'";
     522              : 
     523            0 :                 const ProductProvenance* prdprov = I->second->productProvenance().get();
     524              : 
     525            0 :                 msg->WriteObjectAny(prdprov, prdprov_class);
     526            0 :         }
     527            0 :         TLOG(TLVL_WRITEDATAPRODUCTS, "ArtdaqOutput") << "End:   ArtdaqOutput::writeDataProducts(...)";
     528            0 : }
     529              : 
     530            0 : inline void art::ArtdaqOutput::write(EventPrincipal& ep)
     531              : {
     532              :         //
     533              :         //  Write an Event message.
     534              :         //
     535            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin: ArtdaqOutput::write(EventPrincipal& ep)";
     536            0 :         if (!initMsgSent_)
     537              :         {
     538            0 :                 send_init_message();
     539              :         }
     540              :         //
     541              :         //  Get root classes needed for I/O.
     542              :         //
     543            0 :         static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
     544            0 :         if (run_aux_class == nullptr)
     545              :         {
     546            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write: "  // NOLINT(cert-err60-cpp)
     547            0 :                                                                          "Could not get TClass for art::RunAuxiliary!";
     548              :         }
     549            0 :         static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
     550            0 :         if (subrun_aux_class == nullptr)
     551              :         {
     552            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write: "  // NOLINT(cert-err60-cpp)
     553            0 :                                                                          "Could not get TClass for art::SubRunAuxiliary!";
     554              :         }
     555            0 :         static TClass* event_aux_class = TClass::GetClass("art::EventAuxiliary");
     556            0 :         if (event_aux_class == nullptr)
     557              :         {
     558            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::write: "  // NOLINT(cert-err60-cpp)
     559            0 :                                                                          "Could not get TClass for art::EventAuxiliary!";
     560              :         }
     561              : 
     562              :         // Subrun number starts at 1
     563            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Setting Output Fragment Header Fields";
     564            0 :         auto seqID = (static_cast<uint64_t>(ep.eventID().subRun()) << 32) + ep.eventID().event();
     565              : 
     566            0 :         art::ProcessTag tag("", processName());
     567            0 :         auto res = ep.getMany(art::ModuleContext::invalid(), art::WrappedTypeID::make<artdaq::detail::RawEventHeader>(), art::MatchAllSelector(), tag);
     568              : 
     569            0 :         artdaq::Fragment::timestamp_t ts = 0;
     570              : 
     571            0 :         for (auto const& qr : res)
     572              :         {
     573            0 :                 Handle<artdaq::detail::RawEventHeader> handle{qr};
     574            0 :                 if (handle.isValid())
     575              :                 {
     576            0 :                         if (handle->timestamp > ts) ts = handle->timestamp;
     577              :                 }
     578            0 :         }
     579            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Data Fragment Header Fields: SeqID: " << seqID << ", timestamp: " << ts;
     580              : 
     581              :         //
     582              :         //  Setup message buffer.
     583              :         //
     584            0 :         auto msg = prepareMessage(seqID, ts, artdaq::Fragment::DataFragmentType);
     585              :         //
     586              :         //  Write message type code.
     587              :         //
     588            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Streaming message type code ...";
     589            0 :         msg->WriteULong(static_cast<ULong_t>(artdaq::NetMonHeader::MessageType::Event));
     590            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Finished streaming message type code.";
     591              : 
     592              :         //
     593              :         //  Write RunAuxiliary.
     594              :         //
     595            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Streaming RunAuxiliary ...";
     596            0 :         msg->WriteObjectAny(&ep.subRunPrincipal().runPrincipal().runAux(), run_aux_class);
     597            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Finished streaming RunAuxiliary.";
     598              : 
     599              :         //
     600              :         //  Write SubRunAuxiliary.
     601              :         //
     602            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Streaming SubRunAuxiliary ...";
     603            0 :         msg->WriteObjectAny(&ep.subRunPrincipal().subRunAux(), subrun_aux_class);
     604            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Finished streaming SubRunAuxiliary.";
     605              : 
     606              :         //
     607              :         //  Write EventAuxiliary.
     608              :         //
     609              :         {
     610            0 :                 TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Streaming EventAuxiliary ...";
     611            0 :                 msg->WriteObjectAny(&ep.eventAux(), event_aux_class);
     612            0 :                 TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Finished streaming EventAuxiliary.";
     613              :         }
     614              : 
     615              :         //
     616              :         //  Write data products.
     617              :         //
     618            0 :         std::vector<BranchKey*> bkv;
     619            0 :         writeDataProducts(msg, ep, bkv);
     620              : 
     621            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Sending message";
     622            0 :         sendMessage(msg);
     623            0 :         TLOG(TLVL_WRITE, "ArtdaqOutput") << "ArtdaqOutput::write: Done sending message";
     624              : 
     625              :         //
     626              :         //  Delete the branch keys we created for the message.
     627              :         //
     628            0 :         for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
     629              :         {
     630            0 :                 delete *I;
     631            0 :                 *I = 0;
     632              :         }
     633            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "End: ArtdaqOutput::write(EventPrincipal& ep)";
     634            0 : }
     635              : 
     636            0 : inline void art::ArtdaqOutput::writeSubRun(SubRunPrincipal& srp)
     637              : {  //
     638              :         //  Write an SubRun message.
     639              :         //
     640            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin: ArtdaqOutput::writeSubRun(SubRunPrincipal& srp)";
     641            0 :         if (!initMsgSent_)
     642              :         {
     643              :                 // TLOG(TLVL_WARNING, "ArtdaqOutput") << "Not sending Subrun message before Event!";
     644              :                 // return;
     645            0 :                 send_init_message();
     646              :         }
     647              : 
     648              :         //
     649              :         //  Get root classes needed for I/O.
     650              :         //
     651            0 :         static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
     652            0 :         if (run_aux_class == nullptr)
     653              :         {
     654            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeSubRun: "  // NOLINT(cert-err60-cpp)
     655            0 :                                                                          "Could not get TClass for art::RunAuxiliary!";
     656              :         }
     657            0 :         static TClass* subrun_aux_class = TClass::GetClass("art::SubRunAuxiliary");
     658            0 :         if (subrun_aux_class == nullptr)
     659              :         {
     660            0 :                 throw art::Exception(art::errors::DictionaryNotFound) << "ArtdaqOutput::writeSubRun: "  // NOLINT(cert-err60-cpp)
     661            0 :                                                                          "Could not get TClass for art::SubRunAuxiliary!";
     662              :         }
     663              :         //
     664              :         //  Begin preparing message.
     665              :         //
     666            0 :         auto msg = prepareMessage(static_cast<uint64_t>(srp.subRun()) << 32, srp.subRun() + 1, artdaq::Fragment::SubrunDataFragmentType);
     667              :         //
     668              :         //  Write message type code.
     669              :         //
     670              :         {
     671            0 :                 TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: streaming message type code ...";
     672            0 :                 msg->WriteULong(static_cast<ULong_t>(artdaq::NetMonHeader::MessageType::Subrun));
     673            0 :                 TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: finished streaming message type code.";
     674              :         }
     675              :         //
     676              :         //  Write RunAuxiliary.
     677              :         //
     678            0 :         TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: Streaming RunAuxiliary ...";
     679            0 :         msg->WriteObjectAny(&srp.runPrincipal().runAux(), run_aux_class);
     680            0 :         TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: Finished streaming RunAuxiliary.";
     681              : 
     682              :         //
     683              :         //  Write SubRunAuxiliary.
     684              :         //
     685              :         {
     686            0 :                 TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: streaming SubRunAuxiliary ...";
     687              : 
     688            0 :                 TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: dumping ProcessHistoryRegistry ...";
     689              :                 // typedef std::map<const ProcessHistoryID,ProcessHistory>
     690              :                 //    ProcessHistoryMap;
     691            0 :                 for (auto I = std::begin(art::ProcessHistoryRegistry::get()), E = std::end(art::ProcessHistoryRegistry::get());
     692            0 :                      I != E; ++I)
     693              :                 {
     694            0 :                         std::ostringstream OS;
     695            0 :                         I->first.print(OS);
     696            0 :                         TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: phr: id: '" << OS.str() << "'";
     697            0 :                         OS.str("");
     698            0 :                         TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: phr: data.size():  " << I->second.data().size();
     699            0 :                         if (!I->second.data().empty())
     700              :                         {
     701            0 :                                 I->second.data().back().id().print(OS);
     702            0 :                                 TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: phr: data.back().id(): '" << OS.str() << "'";
     703              :                         }
     704            0 :                 }
     705            0 :                 if (!srp.subRunAux().processHistoryID().isValid())
     706              :                 {
     707            0 :                         TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: ProcessHistoryID: 'INVALID'";
     708              :                 }
     709              :                 else
     710              :                 {
     711            0 :                         std::ostringstream OS;
     712            0 :                         srp.subRunAux().processHistoryID().print(OS);
     713            0 :                         TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: ProcessHistoryID: '" << OS.str() << "'";
     714            0 :                         OS.str("");
     715            0 :                         ProcessHistory processHistory;
     716            0 :                         ProcessHistoryRegistry::get(srp.subRunAux().processHistoryID(), processHistory);
     717            0 :                         if (!processHistory.data().empty())
     718              :                         {
     719              :                                 // FIXME: Print something special on invalid id() here!
     720            0 :                                 processHistory.data().back().id().print(OS);
     721            0 :                                 TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: ProcessConfigurationID: '" << OS.str() << "'";
     722            0 :                                 OS.str("");
     723            0 :                                 OS << processHistory.data().back();
     724            0 :                                 TLOG(TLVL_WRITESUBRUN_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: ProcessConfiguration: '" << OS.str();
     725              :                         }
     726            0 :                 }
     727            0 :                 msg->WriteObjectAny(&srp.subRunAux(), subrun_aux_class);
     728            0 :                 TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: streamed SubRunAuxiliary.";
     729              :         }
     730              :         //
     731              :         //  Write data products.
     732              :         //
     733            0 :         std::vector<BranchKey*> bkv;
     734            0 :         writeDataProducts(msg, srp, bkv);
     735              : 
     736            0 :         TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: Sending message";
     737            0 :         sendMessage(msg);
     738            0 :         TLOG(TLVL_WRITESUBRUN, "ArtdaqOutput") << "ArtdaqOutput::writeSubRun: Done sending message";
     739              : 
     740              :         //
     741              :         //  Delete the branch keys we created for the message.
     742              :         //
     743            0 :         for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
     744              :         {
     745            0 :                 delete *I;
     746            0 :                 *I = 0;
     747              :         }
     748            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "End: ArtdaqOutput::writeSubRun(const SubRunPrincipal& srp)";
     749            0 : }
     750              : 
     751            0 : inline void art::ArtdaqOutput::writeRun(RunPrincipal& rp)
     752              : {  //
     753              :         //  Write an Run message.
     754              :         //
     755            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin: ArtdaqOutput::writeRun(const RunPrincipal& rp)";
     756              :         (void)rp;
     757            0 :         if (!initMsgSent_)
     758              :         {
     759              :                 // TLOG(TLVL_WARNING, "ArtdaqOutput") << "Not sending Run message before Event!";
     760              :                 // return;
     761            0 :                 send_init_message();
     762              :         }
     763              : 
     764              :         //
     765              :         //  Fetch the class dictionaries we need for
     766              :         //  writing out the auxiliary information.
     767              :         //
     768            0 :         static TClass* run_aux_class = TClass::GetClass("art::RunAuxiliary");
     769            0 :         assert(run_aux_class != nullptr && "writeRun: Could not get TClass for art::RunAuxiliary!");
     770              :         //
     771              :         //  Begin preparing message.
     772              :         //
     773            0 :         auto msg = prepareMessage(artdaq::Fragment::InvalidSequenceID - 1, rp.run() + 1, artdaq::Fragment::RunDataFragmentType);
     774              :         //
     775              :         //  Write message type code.
     776              :         //
     777              :         {
     778            0 :                 TLOG(TLVL_WRITERUN, "ArtdaqOutput") << "ArtdaqOutput::writeRun: streaming message type code ...";
     779            0 :                 msg->WriteULong(static_cast<ULong_t>(artdaq::NetMonHeader::MessageType::Run));
     780            0 :                 TLOG(TLVL_WRITERUN, "ArtdaqOutput") << "ArtdaqOutput::writeRun: finished streaming message type code.";
     781              :         }
     782              :         //
     783              :         //  Write RunAuxiliary.
     784              :         //
     785              :         {
     786            0 :                 TLOG(TLVL_WRITERUN, "ArtdaqOutput") << "ArtdaqOutput::writeRun: streaming RunAuxiliary ...";
     787            0 :                 msg->WriteObjectAny(&rp.runAux(), run_aux_class);
     788            0 :                 TLOG(TLVL_WRITERUN, "ArtdaqOutput") << "ArtdaqOutput::writeRun: streamed RunAuxiliary.";
     789              :         }
     790              :         //
     791              :         //  Write data products.
     792              :         //
     793            0 :         std::vector<BranchKey*> bkv;
     794            0 :         writeDataProducts(msg, rp, bkv);
     795              : 
     796            0 :         TLOG(TLVL_WRITERUN, "ArtdaqOutput") << "ArtdaqOutput::writeRun: Sending message";
     797            0 :         sendMessage(msg);
     798            0 :         TLOG(TLVL_WRITERUN, "ArtdaqOutput") << "ArtdaqOutput::writeRun: Done sending message";
     799              : 
     800            0 :         for (auto I = bkv.begin(), E = bkv.end(); I != E; ++I)
     801              :         {
     802            0 :                 delete *I;
     803            0 :                 *I = 0;
     804              :         }
     805            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "End: ArtdaqOutput::writeRun(RunPrincipal& rp)";
     806            0 : }
     807              : 
     808            0 : inline void art::ArtdaqOutput::beginJob()
     809              : {
     810            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "Begin: ArtdaqOutput::beginJob()";
     811            0 :         auto const& products = keptProducts();
     812              : 
     813              :         // std::array<Selections, NumBranchTypes>
     814            0 :         for (auto const& selections : products)
     815              :         {
     816              :                 // Selections = std::map<ProductID, BranchDescription>
     817            0 :                 for (auto const& prod_pair : selections)
     818              :                 {
     819            0 :                         auto const& productDescription = prod_pair.second;
     820            0 :                         auto const& branchKey = BranchKey(productDescription);
     821              : 
     822            0 :                         if (!productList_.count(branchKey))
     823              :                         {
     824            0 :                                 TLOG(TLVL_BEGINJOB_VERBOSE, "ArtdaqOutput") << "ArtdaqOutput::beginJob:"
     825            0 :                                                                             << "Adding branch key to productList of class: '"
     826            0 :                                                                             << branchKey.friendlyClassName_ << "' modlbl: '" << branchKey.moduleLabel_ << "' instnm: '"
     827            0 :                                                                             << branchKey.productInstanceName_ << "' procnm: '" << branchKey.processName_ << "'"
     828            0 :                                                                             << ", description: " << productDescription.wrappedName();
     829              : 
     830            0 :                                 productList_[branchKey] = productDescription;
     831              :                         }
     832            0 :                 }
     833              :         }
     834            0 :         TLOG(TLVL_ENTER_EXIT, "ArtdaqOutput") << "End: ArtdaqOutput::beginJob() Product list sz=" << productList_.size();
     835              : 
     836              :         // send_init_message();
     837            0 : }
     838              : 
     839              : #endif  // ARTDAQ_ARTDAQ_ARTMODULES_ARTDAQOUTPUT_HH_
        

Generated by: LCOV version 2.0-1