diff --git a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
index e778a7736a982b223e085bca97a4c56b21a02154..dbc97d83ec1c01f9eb34d166fbd23ca6d0636466 100644
--- a/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
+++ b/HLT/Trigger/TrigControl/TrigServices/CMakeLists.txt
@@ -22,6 +22,7 @@ atlas_depends_on_subdirs( PUBLIC
                           Trigger/TrigDataAccess/TrigROBDataProviderSvc
                           Trigger/TrigEvent/TrigSteeringEvent
                           PRIVATE
+                          Control/CxxUtils
                           Database/AthenaPOOL/AthenaPoolUtilities
                           Trigger/TrigConfiguration/TrigConfInterfaces
                           Trigger/TrigSteer/TrigOutputHandling )
diff --git a/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py b/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py
index 4f7f02252d2c028da54c2a435c08c49f4d327aae..a50c90630b3443136752af038bb12934fc2c8eb1 100644
--- a/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py
+++ b/HLT/Trigger/TrigControl/TrigServices/python/TrigServicesConfig.py
@@ -35,13 +35,15 @@ class TrigCOOLUpdateHelper(_TrigCOOLUpdateHelper):
 def setupMessageSvc():
    from AthenaCommon.AppMgr import theApp
    from AthenaCommon.AppMgr import ServiceMgr as svcMgr
-   from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, WARNING
+   from AthenaCommon.Constants import VERBOSE, DEBUG, INFO, WARNING, ERROR
 
    svcMgr.MessageSvc = theApp.service( "MessageSvc" )     # already instantiated
    MessageSvc = svcMgr.MessageSvc
    MessageSvc.OutputLevel = theApp.OutputLevel
 
    MessageSvc.Format       = "% F%40W%S%4W%e%s%7W%R%T %0W%M"
+   MessageSvc.ErsFormat    = "%S: %M"
+   MessageSvc.printEventIDLevel = WARNING
 
    # Message suppression
    MessageSvc.enableSuppression    = False
@@ -63,20 +65,12 @@ def setupMessageSvc():
       MessageSvc.defaultLimit = 0
       MessageSvc.enableSuppression = False
 
-   # publish message counts during RUNNING in histogram
-   MessageSvc.publishStats = True
-   MessageSvc.publishLevel = INFO
-
    # show summary statistics of messages in finalize
    MessageSvc.showStats = True
    MessageSvc.statLevel = WARNING
    MessageSvc.statLevelRun = VERBOSE
 
-   # publish message counts during RUNNING in histogram
-   MessageSvc.publishStats = True
-   MessageSvc.publishLevel = INFO
-
-# online ROB data provider service 
+# online ROB data provider service
 from TrigServicesConf import HltROBDataProviderSvc as _HltROBDataProviderSvc
 class HltROBDataProviderSvc(_HltROBDataProviderSvc):
    __slots__ = ()
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx
index e253e0663f7307316a0ec35c01411735fcb765ef..7e8cc47879fe78b2454045516eaa4949ffc9ceef 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 /*
  * This is a copy of GaudiSvc/src/THistSvc with THistSvc renamed to THistSvcHLT
@@ -36,6 +36,8 @@
 // local headers
 #include "THistSvcHLT.h"
 
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;  // copied from Gaudi, no checking
+
 namespace
 {
   template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename UnaryPredicate>
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h
index 5832fc6f574fa0319a9cfa7222498117423f5a67..4623886d31fd89c4d752110aaec9d05bca5f7453 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h
+++ b/HLT/Trigger/TrigControl/TrigServices/src/THistSvcHLT.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 /*
  * This is a copy of GaudiSvc/src/THistSvc with THistSvc renamed to THistSvcHLT
@@ -33,6 +33,9 @@
 
 #include "AthenaBaseComps/AthService.h"
 
+#include "CxxUtils/checker_macros.h"
+ATLAS_NO_CHECK_FILE_THREAD_SAFETY;  // copied from Gaudi, no checking
+
 class IIncidentSvc;
 
 class THistSvcHLT : public extends<AthService, ITHistSvc, IIncidentListener, IIoComponent>
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigHLTIssues.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigHLTIssues.h
deleted file mode 100644
index 3e282bed7f22c33b796532ebbe471a159217b16f..0000000000000000000000000000000000000000
--- a/HLT/Trigger/TrigControl/TrigServices/src/TrigHLTIssues.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Dear emacs, this is -*- c++ -*-
-
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/**
- * @file TrigHLTIssues.h
- * @author <a href="mailto:Werner.Wiedenmann@cern.ch">Werner Wiedenmann</a>
- *
- * @brief ERS issue classes for HLT
- */
-
-#ifndef TRIG_HLT_ISSUES_H
-#define TRIG_HLT_ISSUES_H
-
-#include "ers/ers.h"
-
-ERS_DECLARE_ISSUE( ers, HLTMessage, , )
-ERS_DECLARE_ISSUE( ers, HLTAbort, "Fatal error during event processing", )
-  
-#define ERS_HLT_WARNING( message ) \
-{ \
-    ERS_REPORT_IMPL( ers::warning, ers::HLTMessage, message, ); \
-}
-
-#define ERS_HLT_ERROR( message ) \
-{ \
-    ERS_REPORT_IMPL( ers::error, ers::HLTMessage, message, ); \
-}
-
-#define ERS_HLT_FATAL( message ) \
-{ \
-    ERS_REPORT_IMPL( ers::fatal, ers::HLTMessage, message, ); \
-}
-  
-#endif /* TRIG_HLT_ISSUES_H */
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx
index 6406101bbf0e6e680cbe6025378ef1feecf1871f..d13cc16ef6d871cbf2ea5fcf4583a98d0bc0d2e5 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.cxx
@@ -1,1181 +1,380 @@
 /*
   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
-
+#include "TrigMessageSvc.h"
+#include "GaudiKernel/IAppMgrUI.h"
 #include "GaudiKernel/Kernel.h"
-#include "GaudiKernel/IIncidentSvc.h"
-#include "GaudiKernel/ITHistSvc.h"
-#include "GaudiKernel/StatusCode.h"
 #include "GaudiKernel/Message.h"
-#include "GaudiKernel/IJobOptionsSvc.h"
-#include "EventInfo/EventInfo.h"
-#include "EventInfo/EventID.h"
-#include "TrigMessageSvc.h"
-#include "TrigHLTIssues.h"
-#include "TrigMonitorBase/TrigLockedHist.h"
+#include "GaudiKernel/StatusCode.h"
+#include "GaudiKernel/System.h"
 
-#include <TH1I.h>
-#include <TH2I.h>
+#include "ers/ers.h"
 
-#include <sstream>
+#include <fstream>
 #include <iostream>
+#include <sstream>
 
-#include <pthread.h>
-#include <boost/thread/recursive_mutex.hpp>
-
-
-static pthread_mutex_t msgsvcmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-
-using namespace std;
+// Declare ERS issue type
+ERS_DECLARE_ISSUE(ers, HLTMessage, , )
 
-static std::string levelNames[MSG::NUM_LEVELS];
+static const std::string levelNames[MSG::NUM_LEVELS] = {"NIL",     "VERBOSE", "DEBUG", "INFO",
+                                                        "WARNING", "ERROR",   "FATAL", "ALWAYS"};
 
-// ERS debug level for which to enforce DEBUG OutputLevel
-static int ersGaudiDebugOffset = 8;
+namespace {
+  /// Calculate message hash ignoring any digits
+  size_t msgHash(const Message& msg)
+  {
+    std::string s = msg.getSource() + msg.getMessage();
+    s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return std::isdigit(c); }), s.end());
+    return std::hash<std::string>()(s);
+  }
+} // namespace
 
-// Constructor
-TrigMessageSvc::TrigMessageSvc( const std::string& name, ISvcLocator* svcloc )
-  : base_class(name, svcloc)
-  , m_doSuppress{false}
-  , m_running{false}
-  , m_canEnter{false}
-  , m_evtStore{"StoreGateSvc/StoreGateSvc", name}
-  , m_msgCountHist{nullptr}
-  , m_msgCountSrcHist{nullptr}
+TrigMessageSvc::TrigMessageSvc(const std::string& name, ISvcLocator* svcloc) :
+    base_class(name, svcloc)
 {
-  m_defaultStream = &std::cout;
-  m_outputLevel   = MSG::NIL;
-  declareProperty( "Format",      m_defaultFormat = "% F%18W%S%7W%R%T %0W%M" );
-  declareProperty( "timeFormat",  m_defaultTimeFormat = "%Y-%m-%d %H:%M:%S,%f" );
-
-  declareProperty( "showStats",    m_stats = false );
-  declareProperty( "statLevel",    m_statLevel = 0, "Show statistics for messages >= level" );
-  declareProperty( "statLevelRun", m_statLevelRun = 0, "Show per-run statistics for messages >= level" );
-  
-  declareProperty( "publishStats", m_publishStats = false,
-                   "Publish message statistics as histogram");
-  
-  declareProperty( "publishLevel", m_publishLevel = MSG::INFO,
-                   "Publish message statistics for this and higher message levels");
-  
-  declareProperty( "resetStatsAtBeginRun", m_resetStats = false );  
-
-  declareProperty( "printEventIDLevel", m_eventIDLevel = MSG::WARNING,
-                   "Print event ID for this and higher message levels");
-                   
-  // Special properties to control output level of individual sources
-  declareProperty( "setVerbose",  m_thresholdProp[MSG::VERBOSE] );
-  declareProperty( "setDebug",    m_thresholdProp[MSG::DEBUG] );
-  declareProperty( "setInfo",     m_thresholdProp[MSG::INFO] );
-  declareProperty( "setWarning",  m_thresholdProp[MSG::WARNING] );
-  declareProperty( "setError",    m_thresholdProp[MSG::ERROR] );
-  declareProperty( "setFatal",    m_thresholdProp[MSG::FATAL] );
-  declareProperty( "setAlways",   m_thresholdProp[MSG::ALWAYS] );
-
-  declareProperty( "useColors",        m_color=false);
-  m_color.declareUpdateHandler(&TrigMessageSvc::initColors, this);
-
-  declareProperty( "fatalColorCode",   m_logColors[MSG::FATAL] );
-  declareProperty( "errorColorCode",   m_logColors[MSG::ERROR] );
-  declareProperty( "warningColorCode", m_logColors[MSG::WARNING] );
-  declareProperty( "infoColorCode",    m_logColors[MSG::INFO] );
-  declareProperty( "debugColorCode",   m_logColors[MSG::DEBUG] );
-  declareProperty( "verboseColorCode", m_logColors[MSG::VERBOSE] );
-  declareProperty( "alwaysColorCode",  m_logColors[MSG::ALWAYS] );
-
-  m_defaultLimit = 500;
-  declareProperty( "fatalLimit",    m_msgLimit[MSG::FATAL]   = m_defaultLimit );
-  declareProperty( "errorLimit",    m_msgLimit[MSG::ERROR]   = m_defaultLimit );
-  declareProperty( "warningLimit",  m_msgLimit[MSG::WARNING] = m_defaultLimit );
-  declareProperty( "infoLimit",     m_msgLimit[MSG::INFO]    = m_defaultLimit );
-  declareProperty( "debugLimit",    m_msgLimit[MSG::DEBUG]   = m_defaultLimit );
-  declareProperty( "verboseLimit",  m_msgLimit[MSG::VERBOSE] = m_defaultLimit );
-  declareProperty( "alwaysLimit",   m_msgLimit[MSG::ALWAYS]  = 0 );
+  m_outputLevel.declareUpdateHandler([svcloc](Gaudi::Details::PropertyBase&) {
+    SmartIF<IAppMgrUI> app = svcloc;
+    if (app) app->outputLevelUpdate();
+  });
 
-  declareProperty( "defaultLimit",  m_msgLimit[MSG::NIL]     = m_defaultLimit );
-
-  declareProperty( "enableSuppression", m_suppress = false,
-                   "Enable message suppression");
-  
-  declareProperty( "suppressRunningOnly", m_suppressRunningOnly = true,
-                   "Use message suppression only during RUNNING state");
-
-  m_suppress.declareUpdateHandler(&TrigMessageSvc::setupSuppression, this);
-  m_suppressRunningOnly.declareUpdateHandler(&TrigMessageSvc::setupSuppression, this);
-  
-  /* Special properties to control output to ERS of individual sources.
-     The syntax is as follows (these are NOT regular expressions):
-     
-     useErsFatal = []                       # forward none (default)
-     useErsFatal = ['*']                    # forward all
-     useErsFatal = ['CoreDumpSvc','MyAlg']  # forward these sources
-     useErsFatal = ['*','!MyAlg']           # forward all except MyAlg
-  */
-    
-  const vector<string> defaultErsUse;
-  declareProperty( "useErsVerbose",  m_useERS[MSG::VERBOSE] = defaultErsUse );
-  declareProperty( "useErsDebug",    m_useERS[MSG::DEBUG]   = defaultErsUse );
-  declareProperty( "useErsInfo",     m_useERS[MSG::INFO]    = defaultErsUse );
-  declareProperty( "useErsWarning",  m_useERS[MSG::WARNING] = defaultErsUse );
-  declareProperty( "useErsError",    m_useERS[MSG::ERROR]   = defaultErsUse );
-  declareProperty( "useErsFatal",    m_useERS[MSG::FATAL]   = defaultErsUse );
-  declareProperty( "useErsAlways",   m_useERS[MSG::ALWAYS]  = defaultErsUse );
-
-  declareProperty( "alwaysUseMsgStream", m_alwaysUseMsgStream = true,
-                   "Print all messages to MsgStream, even if forwarded to ERS");
-  
-  declareProperty( "useErsRunningOnly", m_useErsRunningOnly = false,
-                   "Forward messages to ERS only during RUNNING state");  
-                   
-  declareProperty( "forceOutputLevel", m_forceOutputLevel = false,
-                   "Enforce the global OutputLevel for all sources");
-
-  for (int ic=0; ic<MSG::NUM_LEVELS; ++ic) {
-    m_logColors[ic].declareUpdateHandler(&TrigMessageSvc::setupColors, this);
+  for (int ic = 0; ic < MSG::NUM_LEVELS; ++ic) {
     m_msgLimit[ic].declareUpdateHandler(&TrigMessageSvc::setupLimits, this);
     m_thresholdProp[ic].declareUpdateHandler(&TrigMessageSvc::setupThreshold, this);
   }
 
-  levelNames[0] = "NIL";
-  levelNames[1] = "VERBOSE";
-  levelNames[2] = "DEBUG";
-  levelNames[3] = "INFO";
-  levelNames[4] = "WARNING";
-  levelNames[5] = "ERROR";
-  levelNames[6] = "FATAL";
-  levelNames[7] = "ALWAYS";
-
-}
-//#############################################################################
-// Destructor
-TrigMessageSvc::~TrigMessageSvc()
-{
-  pthread_mutex_destroy(&msgsvcmutex);
+  std::fill(std::begin(m_msgCount), std::end(m_msgCount), 0);
 }
 
-/// Initialize Service 
-StatusCode TrigMessageSvc::initialize() {
-
-  StatusCode sc;
-  sc = Service::initialize();
-  if( sc.isFailure() ) return sc;
-  
-  m_running = false;
-  m_canEnter = true;
-  
-#ifdef _WIN32
-  m_color = false;
-#endif  
-  
-  // Reset message counters
-  resetMsgStats();
-  m_sourceMapTotal.clear();
-
-  // Initialize message suppression
-  setupSuppression(m_suppress);
+StatusCode TrigMessageSvc::initialize()
+{
+  StatusCode sc = Service::initialize();
+  if (sc.isFailure()) return sc;
 
-  m_colMap["black"]  = MSG::BLACK;
-  m_colMap["red"]    = MSG::RED;
-  m_colMap["green"]  = MSG::GREEN;
-  m_colMap["yellow"] = MSG::YELLOW;
-  m_colMap["blue"]   = MSG::BLUE;
-  m_colMap["purple"] = MSG::PURPLE;
-  m_colMap["cyan"]   = MSG::CYAN;
-  m_colMap["white"]  = MSG::WHITE;
+  m_doSuppress = m_suppress;
 
-  /*
-   * m_state is set in the base class sysInitialize after initialize succeeded.
-   * However, we need to set it already here otherwise the following
-   * use of IncidentSvc/JobOptionsSvc creates a service initialization loop.
-   */
-  m_state = Gaudi::StateMachine::INITIALIZED;
-
-  /*
-   * This will force the OutputLevel of all components to be the global
-   * OutputLevel (m_outputLevel of this service). It should cover the use-cases:
-   *    1) 'MsgStream(msgSvc(),name())'
-   *    2) 'MsgStream::setLevel(m_outputLevel)'
-   * For 2) we rely on the fact that the MessageSvc is created/initialized after
-   * the JobOptionsSvc in ApplicationMgr::i_startup().
-   */
-  int ers_debug = ers::Configuration::instance().debug_level();
-  if ( ers_debug >= ersGaudiDebugOffset+1 ) {
-    setOutputLevel(MSG::VERBOSE);
-    m_forceOutputLevel.setValue(true);
+  if (m_color) {
+    std::cout << "TrigMessageSvc WARNING: Colors are not supported by TrigMessageSvc" << std::endl;
   }
-  else if ( ers_debug >= ersGaudiDebugOffset ) {
-    setOutputLevel(MSG::DEBUG);
-    m_forceOutputLevel.setValue(true);
-  }
-  
-  if ( m_forceOutputLevel.value() ) {
-    resetOutputLevels();             // Clear all individual OutputLevels (to cover use-case 1)
-    setOutputLevelViaJobOptSvc();    // Set 'OutputLevel' in JobOptionsSvc (to cover use-case 2)
-    reportMessage(name(), MSG::INFO, "Enforcing global OutputLevel = "+levelNames[m_outputLevel.value()]);
-  }
-  
-  // Register incident handlers
-  ServiceHandle<IIncidentSvc> incSvc("IncidentSvc",name());
-  sc = incSvc.retrieve();
-  if (sc.isFailure()) {
-    reportMessage(name(), MSG::WARNING, "Cannot find IncidentSvc");
-  }
-  else {
-    incSvc->addListener(this, "BeginRun", LONG_MAX);
-    incSvc->addListener(this, "EndOfBeginRun", LONG_MAX);
-    incSvc->addListener(this, "EndRun", LONG_MAX);
-  }
-
- return StatusCode::SUCCESS;
+  return StatusCode::SUCCESS;
 }
 
-//#############################################################################
-
-/// Reinitialize Service 
-StatusCode TrigMessageSvc::reinitialize() {
+StatusCode TrigMessageSvc::reinitialize()
+{
   m_state = Gaudi::StateMachine::OFFLINE;
   return initialize();
 }
 
-
-//#############################################################################
-void TrigMessageSvc::handle(const Incident& inc) {
-
-  // We cannot use start/stop for the MessageSvc due to bug #46216
-  if (inc.type()=="BeginRun") {
-    if (m_suppressRunningOnly.value()) {
-      m_doSuppress = m_suppress.value();
-    }
-    if (m_publishStats) bookHistograms();
-  }
-  else if (inc.type()=="EndOfBeginRun") {
-    if (m_resetStats) {
-      reportMessage(name(), MSG::INFO, "Resetting message counts");
-      resetMsgStats();
-    }
-    m_running = true;
-  }
-  else if (inc.type()=="EndRun") {
-    m_running = false;
-    if (m_resetStats) reportMsgStats(MSG::INFO);
-    if (m_suppressRunningOnly.value()) m_doSuppress = false;
-  }
-}
-
-
-//#############################################################################
-void TrigMessageSvc::resetMsgStats()
+void TrigMessageSvc::setupLimits(Gaudi::Details::PropertyBase& prop)
 {
-  // Copy current counts to total counts map
-  std::map<std::string,msgAry>::const_iterator itr;
-  std::map<std::string,msgAry>::iterator tot;
-  for (itr=m_sourceMap.begin(); itr!=m_sourceMap.end(); ++itr) {
-    tot = m_sourceMapTotal.find(itr->first);
-    if (tot==m_sourceMapTotal.end()) {  // new entry
-      for (int i=0; i<MSG::NUM_LEVELS; i++) m_sourceMapTotal[itr->first].msg[i] = itr->second.msg[i];
-    }
-    else {  // existing entry
-      for (int i=0; i<MSG::NUM_LEVELS; i++) tot->second.msg[i] += itr->second.msg[i];
-    }
-  }
-      
-  m_sourceMap.clear();
-  m_msgCountMap.clear();
-  for (int i=0; i<MSG::NUM_LEVELS; i++) m_msgCount[i] = 0;
-}
-
-
-// ---------------------------------------------------------------------------
-// Book the message stats histograms
-// ---------------------------------------------------------------------------
-void TrigMessageSvc::bookHistograms()
-{
-  ServiceHandle<ITHistSvc> histSvc("THistSvc",name());
-  if ( histSvc.retrieve().isFailure() ) {
-    reportMessage(name(), MSG::WARNING,
-                  "Cannot find THistSvc. Message stats will not be published.");
-    return;
-  }
-  
-  // monitoring information root directory
-  const string path = "/EXPERT/" + name() + "/";
-  const int nLevelBins = MSG::NUM_LEVELS - m_publishLevel;
-  m_msgCountHist = new TH1I("MessageCount", "Messages while RUNNING;Severity;Count",
-                            nLevelBins, 0, nLevelBins);
-
-  const int nSrcBins = 1;
-  m_msgCountSrcHist = new TH2I("MessageCountBySource", "Messages while RUNNING;Severity;Source",
-                               nLevelBins, 0, nLevelBins, nSrcBins, 0, nSrcBins);
-
-    
-  for (int i=m_publishLevel; i<MSG::NUM_LEVELS; i++) {
-    m_msgCountHist->GetXaxis()->SetBinLabel(i-m_publishLevel+1, levelNames[i].c_str());
-    m_msgCountSrcHist->GetXaxis()->SetBinLabel(i-m_publishLevel+1, levelNames[i].c_str());    
-  }
-  
-  if ( histSvc->regHist(path + m_msgCountHist->GetName(), m_msgCountHist).isFailure() ) {
-    reportMessage(name(), MSG::WARNING, "Cannot register monitoring histogram 'MessageCount'");
-  }  
-  if ( histSvc->regHist(path + m_msgCountSrcHist->GetName(), m_msgCountSrcHist).isFailure() ) {
-    reportMessage(name(), MSG::WARNING, "Cannot register monitoring histogram 'MessageCountBySource'");
-  }
-}
-
-void TrigMessageSvc::initColors(Property& /*prop*/) {
-
-  if (m_color == true) {
-
-    if (m_logColors[MSG::FATAL].value().size() == 0) {
-      vector<string> fatDef;
-      fatDef.push_back( "[94;101;1m" );
-      m_logColors[MSG::FATAL].set( fatDef );
-    } else {
-      TrigMessageSvc::setupColors( m_logColors[MSG::FATAL] );
-    }
-    
-    if (m_logColors[MSG::ERROR].value().size() == 0) {
-      vector<string> errDef;
-      errDef.push_back( "[97;101;1m" );
-      m_logColors[MSG::ERROR].set( errDef );
-    } else {
-      TrigMessageSvc::setupColors( m_logColors[MSG::ERROR] );
-    }
-    
-    if (m_logColors[MSG::WARNING].value().size() == 0) {
-      vector<string> warDef;
-      warDef.push_back( "[93;1m" );
-      m_logColors[MSG::WARNING].set( warDef );
-    } else {
-      TrigMessageSvc::setupColors( m_logColors[MSG::WARNING] );
-    }
-
-  } else {
-    
-    // reset all color codes;
-    for (int ic=0; ic<MSG::NUM_LEVELS; ++ic) {
-      vector<string> def;
-      m_logColors[ic].set( def );
-    }
-
-  }
-
-}
-
-//#############################################################################
-
-void TrigMessageSvc::setupColors(Property& prop) {
-
-  if (! m_color) return;
-
-  int ic;
-  if (prop.name() == "fatalColorCode") {
-    ic = MSG::FATAL;
-  } else if (prop.name() == "errorColorCode") {
-    ic = MSG::ERROR;
-  } else if (prop.name() == "warningColorCode") {
-    ic = MSG::WARNING;
-  } else if (prop.name() == "infoColorCode") {
-    ic = MSG::INFO;
-  } else if (prop.name() == "debugColorCode") {
-    ic = MSG::DEBUG;
-  } else if (prop.name() == "verboseColorCode") {
-    ic = MSG::VERBOSE;
-  } else if (prop.name() == "alwaysColorCode") {
-    ic = MSG::ALWAYS;
-  } else {
-    std::ostringstream internal_msg ;
-    internal_msg << "ERROR: Unknown message color parameter: " << prop.name();
-    if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
-      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
-    } else {
-      std::cerr << internal_msg.str() << std::endl;
-    }
-    return;
-  }
-
-  string code;
-  vector<string>::const_iterator itr;
-  itr = m_logColors[ic].value().begin();
-
-  if ( m_logColors[ic].value().size() == 1 ) {
-
-    if (*itr == "") {
-      code = "";
-    } else if (itr->substr(0,1) == "[") {
-      code = "\033" + *itr;
-    } else {
-      code = "\033[" + colTrans(*itr, 90) + ";1m";
-    }
-
-  } else if (m_logColors[ic].value().size() == 2) {
-    vector<string>::const_iterator itr2 = itr + 1;
-
-    code =  "\033[" + colTrans(*itr, 90) + ";"
-      + colTrans(*itr2, 100) + ";1m";
-
-  }
-
-  m_logColorCodes[ic] = code; 
-
-}
-//#############################################################################
-
-void TrigMessageSvc::setupLimits(Property& prop) {
-  const auto& pname = prop.name();
-  if (pname == "alwaysLimit") {
-    IntegerProperty *p = dynamic_cast<IntegerProperty*>(&prop);
+  // Just report problems in the settings of the limits and unknown limit
+  // parameters
+  if (prop.name() == "alwaysLimit") {
+    Gaudi::Property<int>* p = dynamic_cast<Gaudi::Property<int>*>(&prop);
     if (p && p->value() != 0) {
-      std::ostringstream internal_msg ;
-      internal_msg << "TrigMessageSvc ERROR: cannot suppress ALWAYS messages" ;
-      if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
-        ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
-      } else {
-        std::cerr << internal_msg.str() << std::endl;
-      }
+      std::cout << "TrigMessageSvc ERROR: cannot suppress ALWAYS messages" << std::endl;
       p->setValue(0);
     }
-  } else if (pname == "defaultLimit") {
-    // Only change the limits that are still on the default value
-    for (int i = MSG::VERBOSE; i< MSG::NUM_LEVELS; ++i) {
-      if ( (i != MSG::ALWAYS) && (m_msgLimit[i].value() == m_defaultLimit) ) {
+  }
+  else if (prop.name() == "defaultLimit") {
+    for (int i = MSG::VERBOSE; i < MSG::NUM_LEVELS; ++i) {
+      if (i != MSG::ALWAYS) {
         m_msgLimit[i] = m_msgLimit[MSG::NIL].value();
       }
     }
-  } else if (pname != "fatalLimit" &&
-             pname != "errorLimit" &&
-             pname != "warningLimit" &&
-             pname != "infoLimit" &&
-             pname != "debugLimit" &&
-             pname != "verboseLimit") {
-    std::ostringstream internal_msg ;
-    internal_msg << "TrigMessageSvc ERROR: Unknown message limit parameter: " << prop.name() ;
-    if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
-      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
-    } else {
-      std::cerr << internal_msg.str() << std::endl;
-    }
-    return;
   }
-}
-//#############################################################################
-
-void TrigMessageSvc::setupThreshold(Property& prop) {
-
-  int ic = 0;
-  if (prop.name() == "setFatal") {
-    ic = MSG::FATAL;
-  } else if (prop.name() == "setError") {
-    ic = MSG::ERROR;
-  } else if (prop.name() == "setWarning") {
-    ic = MSG::WARNING;
-  } else if (prop.name() == "setInfo") {
-    ic = MSG::INFO;
-  } else if (prop.name() == "setDebug") {
-    ic = MSG::DEBUG;
-  } else if (prop.name() == "setVerbose") {
-    ic = MSG::VERBOSE;
-  } else if (prop.name() == "setAlways") {
-    ic = MSG::ALWAYS;
-  } else {
-    std::ostringstream internal_msg ;
-    internal_msg << "TrigMessageSvc ERROR: Unknown message theshold parameter: " << prop.name();
-    if (passErsFilter(name(), m_useERS[MSG::ERROR])) {
-      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
-    } else {
-      std::cerr << internal_msg.str() << std::endl;
-    }
-    return;
-  }
-
-  StringArrayProperty *sap = dynamic_cast<StringArrayProperty*>( &prop);
-  if (sap == 0) {
-    std::ostringstream internal_msg ;
-    internal_msg << "could not dcast " << prop.name() 
-		 << " to a StringArrayProperty (which it should be!)";
-    if (passErsFilter(name(),m_useERS[MSG::ERROR])) {
-      ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
-    } else {
-      std::cerr << internal_msg.str() << std::endl;
-    }
+  else if (prop.name() != "fatalLimit" && prop.name() != "errorLimit" &&
+           prop.name() != "warningLimit" && prop.name() == "infoLimit" &&
+           prop.name() == "debugLimit" && prop.name() == "verboseLimit") {
+    std::cout << "TrigMessageSvc ERROR: Unknown message limit parameter: " << prop.name()
+              << std::endl;
     return;
-  } else {
-    std::vector<std::string>::const_iterator itr;
-    for ( itr =  sap->value().begin();
-	  itr != sap->value().end(); 
-	  ++itr) {
-      setOutputLevel( *itr, ic );
-    }
   }
-
 }
 
-//#############################################################################
-
-bool TrigMessageSvc::passErsFilter(const std::string& source,
-                                   const std::vector<std::string>& filter)
+void TrigMessageSvc::setupThreshold(Gaudi::Details::PropertyBase& prop)
 {
-  if (m_useErsRunningOnly.value() and not m_running) return false;
-  if (filter.empty()) return false;   // forward none
-  vector<string>::const_iterator it = filter.begin();
-  if (filter.size()==1 && (*it)=="*") return true;   // forward all
-
-  bool pass(false);
-  for (; it!=filter.end(); ++it) {
-    if ((*it)=="*") pass=true;           // forward except if there is a veto later
-    if (source==(*it)) return true;      // forward specific source
-    if ("!"+source==(*it)) return false; // veto specific source
+  static const std::array<std::pair<const char*, MSG::Level>, 7> tbl{{{"setFatal", MSG::FATAL},
+                                                                      {"setError", MSG::ERROR},
+                                                                      {"setWarning", MSG::WARNING},
+                                                                      {"setInfo", MSG::INFO},
+                                                                      {"setDebug", MSG::DEBUG},
+                                                                      {"setVerbose", MSG::VERBOSE},
+                                                                      {"setAlways", MSG::ALWAYS}}};
+
+  auto i = std::find_if(
+      std::begin(tbl), std::end(tbl),
+      [&](const std::pair<const char*, MSG::Level>& t) { return prop.name() == t.first; });
+  if (i == std::end(tbl)) {
+    std::cerr << "TrigMessageSvc ERROR: Unknown message threshold parameter: " << prop.name()
+              << std::endl;
+    return;
   }
-  return pass;
-}
-
-  
-//#############################################################################
+  int ic = i->second;
 
-void TrigMessageSvc::setupSuppression(Property& /*prop*/) {
-  // (De)activate suppression
-  if ( m_suppressRunningOnly.value() ) {
-    m_doSuppress = (m_running && m_suppress.value());
+  Gaudi::Property<std::vector<std::string>>* sap =
+      dynamic_cast<Gaudi::Property<std::vector<std::string>>*>(&prop);
+  if (!sap) {
+    std::cerr << "could not dcast " << prop.name()
+              << " to a Gaudi::Property<std::vector<std::string>> (which it "
+                 "should be!)"
+              << std::endl;
   }
   else {
-    m_doSuppress = m_suppress.value();
+    for (auto& i : sap->value()) setOutputLevel(i, ic);
   }
 }
 
-//#############################################################################
-/// Finalize Service
-StatusCode TrigMessageSvc::finalize() {
-
-  m_running = false;
-  m_doSuppress = false;
-  resetMsgStats();  // to get the final total sum
-  reportMsgStats(m_statLevel.value(),true);
-  m_state = Gaudi::StateMachine::OFFLINE;
-  return StatusCode::SUCCESS;
-}
-
-
-//#############################################################################
-/// Report message counts
-void TrigMessageSvc::reportMsgStats(uint statLevel, bool total) {
-
+StatusCode TrigMessageSvc::finalize()
+{
+  m_suppress = false;
   std::ostringstream os;
 
   if (m_stats) {
-    os << "Summarizing all message counts";
-    if (!total){
-      const EventInfo* pEvent(0);
-      if ( m_evtStore->retrieve(pEvent).isSuccess() ) {
-        os  << " for run " << pEvent->event_ID()->run_number();
-      }
-    }	
-    os << " (severity >= " << levelNames[statLevel] << ")" << endl;
-  } else {
-    os << "Listing sources of suppressed message: " << endl;
+    os << "Summarizing all message counts"
+       << " (severity >= " << levelNames[m_statLevel] << ")" << std::endl;
+  }
+  else {
+    os << "Listing sources of suppressed message: " << std::endl;
   }
 
-  os << "==========================================================" << endl;
-  os << " Message Source                   |   Level |    Count" << endl;
-  os << "----------------------------------+---------+-------------" << endl;
+  os << "=====================================================" << std::endl;
+  os << " Message Source              |   Level |    Count" << std::endl;
+  os << "-----------------------------+---------+-------------" << std::endl;
 
   bool found(false);
 
-  std::map<std::string,msgAry>::const_iterator itr = m_sourceMap.begin();
-  std::map<std::string,msgAry>::const_iterator enditr = m_sourceMap.end();
-
-  if (total) {
-    itr = m_sourceMapTotal.begin();
-    enditr = m_sourceMapTotal.end();
-  }
-  
-  for (; itr!=enditr; ++itr) {
+  for (auto itr = m_sourceMap.begin(); itr != m_sourceMap.end(); ++itr) {
     for (unsigned int ic = 0; ic < MSG::NUM_LEVELS; ++ic) {
-      if ( (m_suppress.value() && itr->second.msg[ic] >= abs(m_msgLimit[ic]) && m_msgLimit[ic] != 0 ) || 
-	   (m_stats && itr->second.msg[ic] > 0 && ic >= statLevel) ) {
-	os << " ";
-	os.width(33);
-	os.setf(ios_base::left,ios_base::adjustfield);
-	os << itr->first;
-
-	os << "|";
-
-	os.width(8);
-	os.setf(ios_base::right,ios_base::adjustfield);
-	os << levelNames[ic];
-
-	os << " |";
-
-	os.width(9);
-	os << itr->second.msg[ic];	
-
-	os << endl;
-
-	found = true;
+      if ((m_suppress && itr->second.msg[ic] >= abs(m_msgLimit[ic]) && m_msgLimit[ic] != 0) ||
+          (m_stats && itr->second.msg[ic] > 0 && ic >= m_statLevel.value())) {
+        os << " ";
+        os.width(28);
+        os.setf(std::ios_base::left, std::ios_base::adjustfield);
+        os << itr->first;
+        os << "|";
+
+        os.width(8);
+        os.setf(std::ios_base::right, std::ios_base::adjustfield);
+        os << levelNames[ic];
+        os << " |";
+
+        os.width(9);
+        os << itr->second.msg[ic];
+        os << std::endl;
+
+        found = true;
       }
     }
   }
-  os << "==========================================================" << endl;
-
+  os << "=====================================================" << std::endl;
   if (found || m_stats) {
     reportMessage(name(), MSG::INFO, os.str());
   }
-}
-
-//#############################################################################
-std::string TrigMessageSvc::colTrans(std::string col, int offset) {
-  ColorMap::const_iterator itr = m_colMap.find(col);
-  int icol;
-  if (itr != m_colMap.end()) {
-    icol = offset + itr->second;
-  } else {
-    icol = offset + 8;
-  }
-  std::ostringstream os1;
-      
-  os1 << icol;
-
-  return os1.str();
 
+  return StatusCode::SUCCESS;
 }
 
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: reportMessage
-// Purpose: dispatches a message to the relevant streams.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::reportMessage( const Message& msg, int outputLevel )    {
+void TrigMessageSvc::reportMessage(const Message& msg, int outputLevel)
+{
+  std::unique_lock<std::recursive_mutex> lock(m_reportMutex);
+  i_reportMessage(msg, outputLevel);
+}
 
-  pthread_mutex_lock(&msgsvcmutex);
-  int key = msg.getType();
+/**
+ *  Internal implementation of reportMessage(const Message&,int) without lock.
+ */
+void TrigMessageSvc::i_reportMessage(const Message& msg, int outputLevel)
+{
+  const int key = msg.getType();
   ++m_msgCount[key];
 
-  // Publish message statistics if enabled and only while RUNNING
-  if ( m_publishStats && m_running && key>=static_cast<int>(m_publishLevel) ) {
-    m_msgCountHist->Fill(key-m_publishLevel, 1);
-    { // Adding bins on the fly needs to be protected by mutex
-      scoped_lock_histogram lock;
-      m_msgCountSrcHist->Fill(key-m_publishLevel, msg.getSource().c_str(), 1);
-      m_msgCountSrcHist->LabelsDeflate("Y");
-    }
-  }
+  const Message* cmsg = &msg;
 
-  const Message *cmsg = &msg;
+  if (m_doSuppress || m_stats.value()) {
 
-  if ( m_doSuppress || m_stats.value() ) {
-    int nmsg;    
-    std::map<std::string,msgAry>::iterator itr = m_sourceMap.find(msg.getSource());
-    if ( itr != m_sourceMap.end() ) {
-      nmsg = ++(itr->second.msg[key]);
-    }
-    else {
-      msgAry A;
-      for (int i=0; i<MSG::NUM_LEVELS; ++i) A.msg[i] = 0;
-      A.msg[key] = 1;
-      m_sourceMap[msg.getSource()] = A;
-      nmsg = 1;
-    }
-    
+    // Increase the counter of 'key' type of messages for the source and
+    // get the new value.
+    int nmsg = ++(m_sourceMap[msg.getSource()].msg[key]);
+
+    const int msgLimit = m_msgLimit[key].value();
     if (m_doSuppress) {
-      const int msgLimit = m_msgLimit[key].value();
-      
-      if ( msgLimit > 0 ) {         // regular suppression
-	if (nmsg == msgLimit) {
-          std::ostringstream os;
-          os << levelNames[key] << " message limit (" << msgLimit << ") reached for "
-             << msg.getSource() + ". Suppressing further output.";
-	  cmsg = new Message(msg.getSource(), MSG::WARNING, os.str());
-	  cmsg->setFormat(msg.getFormat());
-          cmsg->setTimeFormat(msg.getTimeFormat());
-	}
-        else if (nmsg > msgLimit) {
-          pthread_mutex_unlock(&msgsvcmutex);
-          return;
+      if (msgLimit > 0) { // regular suppression
+        if (nmsg > msgLimit) return;
+        if (nmsg == msgLimit) {
+          std::string txt = levelNames[key] + " message limit (" + std::to_string(msgLimit) +
+                            ") reached for " + msg.getSource() + ". Suppressing further output.";
+          cmsg = new Message(msg.getSource(), MSG::WARNING, std::move(txt));
         }
       }
-      else if ( msgLimit < 0 ) {    // logarithmic suppression
-
-        // Use source/level/message as identifier and calculate hash
-        const unsigned int msgKey = msgHash(*cmsg);
-        MsgCountMap::iterator itr = m_msgCountMap.find(msgKey);
-        
-        // Check if we saw this message already and increase counter
-        if (itr != m_msgCountMap.end())
-          nmsg = ++itr->second;
-        else
-          nmsg = m_msgCountMap[msgKey] = 1;
-
-        if ( nmsg == abs(msgLimit) ) {
+    }
+    else if (msgLimit < 0) { // logarithmic suppression
+      // Calculate message hash
+      const unsigned int mh = msgHash(*cmsg);
+      // Check if we saw this message already and increase counter
+      auto m = m_msgHashCount.find(mh);
+      if (m != m_msgHashCount.end()) {
+        nmsg = ++m->second;
+      }
+      else {
+        nmsg = m_msgHashCount[mh] = 1;
+      }
+      if (nmsg == abs(msgLimit)) {
+        std::ostringstream os;
+        os << msg.getMessage() << " [Message limit (" << abs(msgLimit)
+           << ") reached. Log-suppression of further output.]";
+        cmsg = new Message(msg.getSource(), msg.getType(), os.str());
+      }
+      else if (nmsg > abs(msgLimit)) {
+        const int everyNth = (int)exp10((int)log10(nmsg));
+        if ((nmsg % everyNth) == 0) {
           std::ostringstream os;
-          os << msg.getMessage() << " [Message limit (" << abs(msgLimit)
-             << ") reached. Log-suppression of further output.]";
+          os << msg.getMessage() << " [suppressed " << everyNth << " similar messages]";
           cmsg = new Message(msg.getSource(), msg.getType(), os.str());
-          cmsg->setFormat(msg.getFormat());
-          cmsg->setTimeFormat(msg.getTimeFormat());
-        }
-        else if ( nmsg > abs(msgLimit) ) {          
-          const int everyNth = (int)exp10((int)log10(nmsg));
-          if ((nmsg % everyNth)==0) {
-            std::ostringstream os;
-            os << msg.getMessage() << " [suppressed " << everyNth << " similar messages]";
-            cmsg = new Message(msg.getSource(), msg.getType(), os.str());
-            cmsg->setFormat(msg.getFormat());
-            cmsg->setTimeFormat(msg.getTimeFormat());
-          }
-          else {
-            pthread_mutex_unlock(&msgsvcmutex);
-            return;
-          }
         }
       }
     }
-  }   // suppression
-
-  // Optional message trailer (ignored in hash)
-  std::ostringstream msgTrailer;
-
-  // Avoid recursion in case StoreGateSvc::retrieve prints a message
-  if ( m_canEnter ) {
-    m_canEnter = false;
-    if ( m_running &&
-         key >= static_cast<int>(m_eventIDLevel.value()) &&
-         m_evtStore.retrieve().isSuccess() ) {
-      const EventInfo* pEvent(0);
-      if ( m_evtStore->retrieve(pEvent).isSuccess() ) {
-        // Add EventID
-        msgTrailer << " " << *pEvent->event_ID();
-      }
-    }
-    m_canEnter = true;
   }
 
-  StreamMap::const_iterator first = m_streamMap.lower_bound( key );
-  if ( first != m_streamMap.end() ) {
-    StreamMap::const_iterator last = m_streamMap.upper_bound( key );
-    while( first != last ) {
-      std::ostream& stream = *( (*first).second.second );
-      stream << *cmsg << msgTrailer.str() << std::endl;
-      ++first;
+  // Print the message
+  if (key >= outputLevel) {
+    if (m_eventIDLevel != MSG::NIL && key >= static_cast<int>(m_eventIDLevel)) {
+      cmsg->setFormat(m_defaultFormat + " %E");
     }
-  }
-  else if ( key >= outputLevel )   {
-    cmsg->setFormat(m_defaultFormat);
-    cmsg->setTimeFormat(m_defaultTimeFormat);
-    std::ostringstream out_string_stream ;
-    if (!m_color) {
-      (out_string_stream) << *cmsg << msgTrailer.str();
-    } else {
-      (out_string_stream) <<  m_logColorCodes[key] << *cmsg << msgTrailer.str() << "\033[m" ;
+    else {
+      cmsg->setFormat(m_defaultFormat);
     }
+    cmsg->setTimeFormat(m_defaultTimeFormat);
+    (*m_defaultStream) << *cmsg << std::endl << std::flush;
 
-    bool useERS = passErsFilter(cmsg->getSource(), m_useERS[key]);
-    
-    if ( m_alwaysUseMsgStream.value() || !useERS ) {
-      // output to the default stream
-      (*m_defaultStream) << out_string_stream.str() << std::endl << std::flush;
+    // ERS forwarding
+    if (passErsFilter(cmsg->getSource(), m_useERS[key])) {
+      i_reportERS(*cmsg);
     }
+  }
 
-    // output to ERS
-    if (useERS) {
-      
-      /*
-       * Create ERS context object
-       *
-       * The (cross-node) MRS throttling is based on filename+line_number, i.e. ignoring
-       * the message text itself. We therefor use the message source as filename and the
-       * message hash as line_number. That way the same message from different nodes
-       * gets properly throttled by MRS.
-       */
-      const char* filename = cmsg->getSource().c_str();
-      unsigned int line_number = msgHash(*cmsg);
-      const char* function_name = filename;
-      const char* package_name = "HLT";
-      ers::LocalContext hlt_context_info(package_name, filename, line_number, function_name);
-
-      /*
-       * Create ERS issue object
-       *
-       * Add the source to the ERS message text. Otherwise the source is not visible
-       * in the MRS monitor, for example.
-       * The "HLT" qualifier can be used to filter ERS messages from the log file.
-       */
-      ers::HLTMessage ersMsg(hlt_context_info, cmsg->getSource() + ": " +  cmsg->getMessage() + msgTrailer.str());
-      ersMsg.add_qualifier("HLT");   // used for filtering
-      
-      // forward Gaudi message to ERS
-      switch (key) {
-        case MSG::NIL:      ers::debug( ersMsg, 3 ); break;
-        case MSG::VERBOSE:  ers::debug( ersMsg, 2 ); break;
-        case MSG::DEBUG:    ers::debug( ersMsg, 1 ); break;
-        case MSG::INFO:     ers::info( ersMsg );     break;
-        case MSG::WARNING:  ers::warning( ersMsg );  break;
-        case MSG::ERROR:    ers::error( ersMsg );    break;
-        case MSG::FATAL:    ers::fatal( ersMsg );    break;
-        default:
-          std::ostringstream internal_msg ;
-          internal_msg << "ERROR: Unknown message severity level: " << key ;
-          ers::error( ers::HLTMessage(ERS_HERE,internal_msg.str()) );
-      }
-    }
+  if (cmsg != &msg) {
+    delete cmsg;
   }
-  
-  if (cmsg != &msg) { delete cmsg; }
-  pthread_mutex_unlock(&msgsvcmutex);
 }
 
-
-void TrigMessageSvc::reportMessage( const Message& msg )
+/**
+ * Report message to online messaging system (ERS)
+ */
+void TrigMessageSvc::i_reportERS(const Message& msg) const
 {
-  reportMessage(msg, outputLevel(msg.getSource()));
-}
-
-void TrigMessageSvc::reportMessage (const char* source,
-                                int type,
-                                const char* message) {
-  Message msg( source, type, message);
-  reportMessage( msg );
-}
-
-
-void TrigMessageSvc::reportMessage (const std::string& source,
-                                int type,
-                                const std::string& message) {
-  Message msg( source, type, message);
-  reportMessage( msg );
-}
-
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: sendMessage
-// Purpose: finds a message for a given status code and dispatches it.
-// ---------------------------------------------------------------------------
-//
+  /*
+   * Create ERS context object
+   *
+   * The (cross-node) MRS throttling is based on filename+line_number, i.e.
+   * ignoring the message text itself. We therefor use the message source as
+   * filename and the message hash as line_number. That way the same message
+   * from different nodes gets properly throttled by MRS.
+   */
+  const char* filename = msg.getSource().c_str();
+  const char* function_name = "";
+  const int line_number = msgHash(msg);
+  const char* package_name = "HLT";
+  ers::LocalContext hlt_context_info(package_name, filename, line_number, function_name);
 
-void TrigMessageSvc::reportMessage (const StatusCode& key,
-                                const std::string& source)
-{  
-  pthread_mutex_lock(&msgsvcmutex);
-  MessageMap::const_iterator first = m_messageMap.lower_bound( key );
-  if ( first != m_messageMap.end() ) {
-    MessageMap::const_iterator last = m_messageMap.upper_bound( key );
-    while( first != last ) {
-      Message msg = (*first).second;
-      msg.setSource( source );
-      std::ostringstream os1;
-      os1 << "Status Code " << key.getCode() << std::ends;
-      Message stat_code1( source, msg.getType(), os1.str() );
-      reportMessage( stat_code1 );
-      reportMessage( msg );
-      ++first;
-    }
+  // Create ERS issue object
+  Message m(msg);
+  if (m_eventIDLevel != MSG::NIL && msg.getType() >= static_cast<int>(m_eventIDLevel)) {
+    m.setFormat(m_ersFormat + " %E");
   }
   else {
-    Message mesg = m_defaultMessage;
-    mesg.setSource( source );
-      std::ostringstream os2;
-    os2 << "Status Code " << key.getCode() << std::ends;
-    Message stat_code2( source,  mesg.getType(), os2.str() );
-    reportMessage( stat_code2 );
-    reportMessage( mesg );
-  }
-  pthread_mutex_unlock(&msgsvcmutex);
-}
-
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: insertStream
-// Purpose: inserts a stream for a message type.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::insertStream (int key,
-                               const std::string& name,
-                               std::ostream *stream)
+    m.setFormat(m_ersFormat);
+  }
+  std::ostringstream oss;
+  oss << m;
+  ers::HLTMessage ersMsg(hlt_context_info, oss.str());
+  ersMsg.add_qualifier("HLT"); // useful for filtering
+
+  // Forward Message to ERS
+  switch (msg.getType()) {
+  case MSG::NIL: break;
+  case MSG::VERBOSE: ers::debug(ersMsg, 2); break;
+  case MSG::DEBUG: ers::debug(ersMsg, 1); break;
+  case MSG::INFO: ers::info(ersMsg); break;
+  case MSG::WARNING: ers::warning(ersMsg); break;
+  case MSG::ERROR: ers::error(ersMsg); break;
+  case MSG::FATAL: ers::fatal(ersMsg); break;
+  default:
+    std::ostringstream oss;
+    oss << "Unknown message severity level: " << msg.getType() << " Original message was: " << m;
+    ers::error(ers::HLTMessage(ERS_HERE, oss.str()));
+  }
+}
+
+void TrigMessageSvc::reportMessage(const Message& msg)
 {
-  typedef StreamMap::value_type value_type;
-  pthread_mutex_lock(&msgsvcmutex);  
-  m_streamMap.insert( value_type( key, NamedStream(name,stream) ) );
-  pthread_mutex_unlock(&msgsvcmutex);
+  reportMessage(msg, outputLevel(msg.getSource()));
 }
 
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseStream
-// Purpose: erases all the streams for all the message types.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseStream()
+void TrigMessageSvc::reportMessage(const char* source, int type, const char* message)
 {
-  pthread_mutex_lock(&msgsvcmutex);
-  m_streamMap.erase( m_streamMap.begin(), m_streamMap.end() );
-  pthread_mutex_unlock(&msgsvcmutex);
+  reportMessage(Message{source, type, message});
 }
 
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseStream
-// Purpose: erases all the streams for a message type.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseStream( int message_type )
+void TrigMessageSvc::reportMessage(const std::string& source, int type, const std::string& message)
 {
-  pthread_mutex_lock(&msgsvcmutex);
-  m_streamMap.erase( message_type );
-  pthread_mutex_unlock(&msgsvcmutex);
+  reportMessage(Message{source, type, message});
 }
 
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseStream
-// Purpose: erases one stream for a message type.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseStream( int key, std::ostream* stream )   {
-  pthread_mutex_lock(&msgsvcmutex);
-  if ( 0 != stream )    {
-    bool changed = true;
-    while( changed ) {
-      changed = false;
-      StreamMap::iterator first = m_streamMap.lower_bound( key );
-      StreamMap::iterator last = m_streamMap.upper_bound( key );
-      while( first != last ) {
-        if ( (*first).second.second == stream ) {
-          m_streamMap.erase( first );
-          changed = true;
-          break;
-        }
-      }
-    }      
-  }
-  pthread_mutex_unlock(&msgsvcmutex);
-}
-
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseStream
-// Purpose: erases one stream for all message types.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseStream( std::ostream* stream )    {
-  pthread_mutex_lock(&msgsvcmutex);
-  if ( 0 != stream )    {
-    bool changed = true;
-    while( changed ) {
-      changed = false;
-      StreamMap::iterator first = m_streamMap.begin();
-      while( first != m_streamMap.end() ) {
-        if ( (*first).second.second == stream ) {
-          m_streamMap.erase( first );
-          changed = true;
-          break;
-        }
-      }
-    }      
-  }
-  pthread_mutex_unlock(&msgsvcmutex);
-}
-
-
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: insertMessage
-// Purpose: inserts a message for a status code.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::insertMessage( const StatusCode& key, const Message& msg )
+int TrigMessageSvc::outputLevel() const
 {
-  typedef MessageMap::value_type value_type;
-  pthread_mutex_lock(&msgsvcmutex);  
-  m_messageMap.insert( value_type( key, msg ) );
-  pthread_mutex_unlock(&msgsvcmutex);
-}
-
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseMessage
-// Purpose: erases all the messages for all the status codes.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseMessage()
-{
-  pthread_mutex_lock(&msgsvcmutex);  
-  m_messageMap.erase( m_messageMap.begin(), m_messageMap.end() );
-  pthread_mutex_unlock(&msgsvcmutex);
+  return m_outputLevel;
 }
 
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseMessage
-// Purpose: erases all the messages for a status code.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseMessage( const StatusCode& key )
+int TrigMessageSvc::outputLevel(const std::string& source) const
 {
-  pthread_mutex_lock(&msgsvcmutex);
-  m_messageMap.erase( key );
-  pthread_mutex_unlock(&msgsvcmutex);
+  std::unique_lock<std::recursive_mutex> lock(m_thresholdMapMutex);
+  auto it = m_thresholdMap.find(source);
+  return it != m_thresholdMap.end() ? it->second : m_outputLevel.value();
 }
 
-//#############################################################################
-// ---------------------------------------------------------------------------
-// Routine: eraseMessage
-// Purpose: erases one message for a status code.
-// ---------------------------------------------------------------------------
-//
-
-void TrigMessageSvc::eraseMessage( const StatusCode& key, const Message& msg )
+void TrigMessageSvc::setOutputLevel(int new_level)
 {
-  pthread_mutex_lock(&msgsvcmutex);
-  bool changed = true;
-  while( changed ) {
-    changed = false;
-    MessageMap::iterator first = m_messageMap.lower_bound( key );
-    MessageMap::iterator last = m_messageMap.upper_bound( key );
-    while( first != last ) {
-      const Message& message = (*first).second;
-      if ( message == msg ) {
-        m_messageMap.erase( first );
-        changed = true;
-        break;
-      }
-    }      
-  }
-  pthread_mutex_unlock(&msgsvcmutex);
-}
-
-// ---------------------------------------------------------------------------
-int TrigMessageSvc::outputLevel()   const {
-// ---------------------------------------------------------------------------
-  return m_outputLevel;
-}
-// ---------------------------------------------------------------------------
-int TrigMessageSvc::outputLevel( const std::string& source )   const {
-// ---------------------------------------------------------------------------
-  ThresholdMap::const_iterator it;
-
-  pthread_mutex_lock(&msgsvcmutex);
-  it = m_thresholdMap.find( source );
-  int level;
-
-  if( it != m_thresholdMap.end() ) {
-    level = (*it).second;
-  }
-  else {
-    level = m_outputLevel;
-  }
-  pthread_mutex_unlock(&msgsvcmutex);
-  return level;
-}
-
-// ---------------------------------------------------------------------------
-void TrigMessageSvc::setOutputLevel(int new_level)    {
-// ---------------------------------------------------------------------------
-  pthread_mutex_lock(&msgsvcmutex);  
   m_outputLevel = new_level;
-  pthread_mutex_unlock(&msgsvcmutex);
-}
-
-// ---------------------------------------------------------------------------
-void TrigMessageSvc::setOutputLevel(const std::string& source, int level)    {
-// ---------------------------------------------------------------------------
-  // Ignore in case we enforce the global OutputLevel
-  if (m_forceOutputLevel.value()) return;
-  
-  pthread_mutex_lock(&msgsvcmutex);
-  std::pair<ThresholdMap::iterator, bool> p;
-  p = m_thresholdMap.insert(ThresholdMap::value_type( source, level) );
-  if( p.second == false ) {
-    // Already existing an output level for that source. Erase and enter it again
-    m_thresholdMap.erase ( p.first );
-    m_thresholdMap.insert(ThresholdMap::value_type( source, level) );
-  }
-  pthread_mutex_unlock(&msgsvcmutex);
 }
 
+void TrigMessageSvc::setOutputLevel(const std::string& source, int level)
+{
+  std::unique_lock<std::recursive_mutex> lock(m_thresholdMapMutex);
 
-// ---------------------------------------------------------------------------
-void TrigMessageSvc::setOutputLevelViaJobOptSvc() {
-// ---------------------------------------------------------------------------
-  ServiceHandle<IJobOptionsSvc> jobOptSvc("JobOptionsSvc", name());    
-  if ( jobOptSvc.retrieve()==StatusCode::FAILURE ) {
-    reportMessage(name(), MSG::ERROR, "Cannot retrieve JobOptionsSvc");
-    return;
+  // only write if we really have to...
+  auto i = m_thresholdMap.find(source);
+  if (i == m_thresholdMap.end()) {
+    m_thresholdMap[source] = level;
   }
-
-  std::vector<std::string> clients = jobOptSvc->getClients();
-  std::vector<std::string>::iterator cl;
-  std::vector<const Property*>::const_iterator pr;
-  
-  // Loop over all clients/properties and set OutputLevel accordingly
-  for (cl=clients.begin(); cl!=clients.end(); ++cl) {
-    const std::vector<const Property*> *props = jobOptSvc->getProperties(*cl);
-    for (pr=props->begin(); pr!=props->end(); ++pr) {
-      if ( (*pr)->name()=="OutputLevel" ) {        
-        if ( jobOptSvc->addPropertyToCatalogue(*cl, m_outputLevel).isSuccess() ){
-          std::ostringstream msg;
-          msg << "Setting " << (*pr)->name() << ".OutputLevel = " << m_outputLevel.value();
-          reportMessage(name(), MSG::DEBUG, msg.str());
-        }
-        else {
-          std::ostringstream msg;
-          msg << "Cannot set " << (*pr)->name() << ".OutputLevel";
-          reportMessage(name(), MSG::WARNING, msg.str());
-        }
-      }
-    }
+  else if (i->second != level) {
+    i->second = level;
   }
 }
-                                                               
-// ---------------------------------------------------------------------------
-void TrigMessageSvc::resetOutputLevels()    {
-// ---------------------------------------------------------------------------
-  m_thresholdMap.clear();  
-}
 
-// ---------------------------------------------------------------------------
-std::string TrigMessageSvc::getLogColor(int logLevel) const   {
-// ---------------------------------------------------------------------------
-  if (logLevel < MSG::NUM_LEVELS) {
-    return m_logColorCodes[logLevel];
-  } else {
-    return "";
-  }
+void TrigMessageSvc::resetOutputLevels()
+{
+  std::unique_lock<std::recursive_mutex> lock(m_thresholdMapMutex);
+  m_thresholdMap.clear();
 }
 
-// ---------------------------------------------------------------------------
-int TrigMessageSvc::messageCount( MSG::Level level) const   {
+int TrigMessageSvc::messageCount(MSG::Level level) const
+{
   return m_msgCount[level];
 }
-// ---------------------------------------------------------------------------
 
-
-// ---------------------------------------------------------------------------
-// Calculate message hash (ignoring any numbers)
-// ---------------------------------------------------------------------------
-unsigned int TrigMessageSvc::msgHash(const Message& msg)
+bool TrigMessageSvc::passErsFilter(const std::string& source,
+                                   const std::vector<std::string>& filter) const
 {
-  // Message type is lowest decimal
-  unsigned int hash = msg.getType();
-  
-  // Add all characters of source
-  const std::string& src = msg.getSource();
-  for (size_t i=0; i<src.length(); ++i) {
-    hash += 10*(int)src[i];
-  }
+  if (filter.empty()) return false; // forward none
+  auto it = filter.begin();
+  if (filter.size() == 1 && (*it) == "*") return true; // forward all
 
-  // Add all letters of message
-  const std::string& str = msg.getMessage();
-  for (size_t i=0; i<str.length(); ++i) {
-    const char& ch = str[i];
-    if (ch<',' || ch>'9') hash += 10*(int)ch;
+  bool pass(false);
+  for (; it != filter.end(); ++it) {
+    if ((*it) == "*") pass = true;           // forward except if there is a veto later
+    if (source == (*it)) return true;        // forward specific source
+    if ("!" + source == (*it)) return false; // veto specific source
   }
-     
-  return hash;
+  return pass;
 }
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.h b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.h
index b64914f57314f51db58b7454d77cfdc45f0f375a..3791d6b1aeeec3283ccc9cf8d7afa88d28d931cb 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.h
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMessageSvc.h
@@ -1,31 +1,33 @@
 /*
   Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
-
 #ifndef TRIGSERVICES_TRIGMESSAGESVC_H
 #define TRIGSERVICES_TRIGMESSAGESVC_H
 
 // Include files
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
 #include <string>
 #include <vector>
-#include <map>
 
-#include "GaudiKernel/StatusCode.h"
-#include "GaudiKernel/Service.h"
-#include "GaudiKernel/ServiceHandle.h"
+#include "CxxUtils/checker_macros.h"
 #include "GaudiKernel/IMessageSvc.h"
-#include "GaudiKernel/IIncidentListener.h"
 #include "GaudiKernel/Message.h"
 #include "GaudiKernel/Property.h"
-
-#include "StoreGate/StoreGateSvc.h"
+#include "GaudiKernel/Service.h"
+#include "GaudiKernel/StatusCode.h"
 
 #include "TrigKernel/ITrigMessageSvc.h"
 
+// Helper to mark some virtual methods as not supported
+#define NOTSUPPORTED                                                                               \
+  throw std::logic_error(std::string(__func__) + " is not supported by TrigMessageSvc")
+
 // Forward declarations
 class ISvcLocator;
-class TH1I;
-class TH2I;
 
 /**@class TrigMessageSvc
  * @brief MessageSvc used by the HLT applications
@@ -44,172 +46,147 @@ class TH2I;
  *
  * @author    Iain Last, Werner Wiedenmann, Frank Winklmeier
  */
+class TrigMessageSvc : public extends<Service, IMessageSvc, ITrigMessageSvc> {
+public:
+  typedef std::map<std::string, int> ThresholdMap;
+
+  TrigMessageSvc(const std::string& name, ISvcLocator* svcloc);
 
-class TrigMessageSvc : public extends<Service,IMessageSvc,ITrigMessageSvc,IIncidentListener> {
-public:  
-  typedef std::pair< std::string, std::ostream* > NamedStream;
-  typedef std::multimap< int, NamedStream > StreamMap;
-  typedef std::multimap< StatusCode, Message > MessageMap;
-  typedef std::map< std::string, int > ThresholdMap;
-  
-  // Default constructor.
-  TrigMessageSvc( const std::string& name, ISvcLocator* svcloc );
-  // Destructor.
-  virtual ~TrigMessageSvc();
-
-  // Implementation of IService::reinitialize()
   virtual StatusCode reinitialize() override;
-  // Implementation of IService::initialize()
   virtual StatusCode initialize() override;
-  // Implementation of IService::finalize()
   virtual StatusCode finalize() override;
 
-  // Implementation of IMessageSvc::reportMessage()
-  virtual void reportMessage( const Message& message ) override;
-
-  // Implementation of IMessageSvc::reportMessage()
-  virtual void reportMessage( const Message& message, int outputLevel ) override;
-
-  // Implementation of IMessageSvc::reportMessage()
-  virtual void reportMessage( const StatusCode& code, const std::string& source = "") override;
-
-  // Implementation of IMessageSvc::reportMessage()
-  virtual void reportMessage( const char* source, int type, const char* message) override;
-
-  // Implementation of IMessageSvc::reportMessage()
-  virtual void reportMessage( const std::string& source, int type, const std::string& message) override;
-  
-  // Implementation of IMessageSvc::insertMessage()
-  virtual void insertMessage( const StatusCode& code, const Message& message ) override;
-
-  // Implementation of IMessageSvc::eraseMessage()
-  virtual void eraseMessage() override;
-
-  // Implementation of IMessageSvc::eraseMessage()
-  virtual void eraseMessage( const StatusCode& code ) override;
-
-  // Implementation of IMessageSvc::eraseMessage()
-  virtual void eraseMessage( const StatusCode& code, const Message& message ) override;
-
-  // Implementation of IMessageSvc::insertStream()
-  virtual void insertStream( int message_type, const std::string& name, std::ostream* stream ) override;
-  
-  // Implementation of IMessageSvc::eraseStream()
-  virtual void eraseStream() override;
-  
-  // Implementation of IMessageSvc::eraseStream()
-  virtual void eraseStream( int message_type ) override;
-  
-  // Implementation of IMessageSvc::eraseStream()
-  virtual void eraseStream( int message_type, std::ostream* stream ) override;
-
-  // Implementation of IMessageSvc::eraseStream()
-  virtual void eraseStream( std::ostream* stream ) override;
-
-  // Implementation of IMessageSvc::desaultStream()
-  virtual std::ostream* defaultStream() const override {
-    return m_defaultStream; 
+  virtual void reportMessage(const Message& message) override;
+  virtual void reportMessage(const Message& msg, int outputLevel) override;
+  virtual void reportMessage(const char* source, int type, const char* message) override;
+  virtual void reportMessage(const std::string& source, int type,
+                             const std::string& message) override;
+  virtual std::ostream* defaultStream ATLAS_NOT_THREAD_SAFE() const override
+  {
+    return m_defaultStream;
   }
 
-  // Implementation of IMessageSvc::setDefaultStream()
-  virtual void setDefaultStream( std::ostream* stream ) override {
+  virtual void setDefaultStream(std::ostream* stream) override
+  {
+    std::unique_lock<std::recursive_mutex> lock(m_reportMutex);
     m_defaultStream = stream;
   }
 
-  // Implementation of IMessageSvc::ouputLevel()
-  virtual int outputLevel()   const override;
-
-  // Implementation of IMessageSvc::ouputLevel()
-  virtual int outputLevel(const std::string& source)   const override;
-
-  // Implementation of IMessageSvc::setOuputLevel()
+  virtual int outputLevel() const override;
+  virtual int outputLevel(const std::string& source) const override;
   virtual void setOutputLevel(int new_level) override;
-
-  // Implementation of IMessageSvc::setOuputLevel()
   virtual void setOutputLevel(const std::string& source, int new_level) override;
-
-  // Implementation of IMessageSvc::useColor()
-  virtual bool useColor() const override { return m_color; }
-
-  // Implementation of IMessageSvc::getLogColor()
-  virtual std::string getLogColor(int logLevel) const override;
-
-  // Implementation of IMessageSvc::messageCount()
-  virtual int messageCount( MSG::Level logLevel ) const override;
- 
-  /// \name ITrigMessageSvc implementation
-  //@{
-  /// Reset all individual output levels
+  virtual int messageCount(MSG::Level logLevel) const override;
   virtual void resetOutputLevels() override;
-  //@}
 
-  // Implemenation of IIncidentListener::handle()
-  virtual void handle(const Incident& inc) override;
+  virtual bool useColor() const override { return m_color; }
+  virtual std::string getLogColor(int) const override { return ""; }
+
+  ///@{ Not supported by this implementation
+  virtual void reportMessage(const StatusCode&, const std::string&) override { NOTSUPPORTED; }
+  virtual void insertMessage(const StatusCode&, const Message&) override { NOTSUPPORTED; }
+  virtual void eraseMessage() override { NOTSUPPORTED; }
+  virtual void eraseMessage(const StatusCode&) override { NOTSUPPORTED; }
+  virtual void eraseMessage(const StatusCode&, const Message&) override { NOTSUPPORTED; }
+  virtual void insertStream(int, const std::string&, std::ostream*) override { NOTSUPPORTED; }
+  virtual void eraseStream() override { NOTSUPPORTED; }
+  virtual void eraseStream(int) override { NOTSUPPORTED; }
+  virtual void eraseStream(int, std::ostream*) override { NOTSUPPORTED; }
+  virtual void eraseStream(std::ostream*) override { NOTSUPPORTED; }
+  ///@}
 
 private:
-  typedef std::map<std::string, MSG::Color> ColorMap;
-  typedef std::map< unsigned int, unsigned int > MsgCountMap;
-  
-  std::ostream* m_defaultStream;      ///< Pointer to the output stream.
-  Message m_defaultMessage;           ///< Default Message
-  StreamMap m_streamMap;              ///< Stream map
-  MessageMap m_messageMap;            ///< Message map
-  ThresholdMap m_thresholdMap;        ///< Output level threshold map
-  std::string m_defaultFormat;        ///< Default format for the messages
-  std::string m_defaultTimeFormat;    ///< Default time format for the messages
-  int m_defaultLimit;                 ///< Original default message limit
-  bool m_doSuppress;                  ///< Message suppression currently active?
-  bool m_running;                     ///< In RUNNING state
-  bool m_canEnter;                    ///< used to avoid infinite recursions
-  
-  ServiceHandle<StoreGateSvc> m_evtStore;   ///< Event store
-  
-  /* Properties */
-  StringArrayProperty m_thresholdProp[MSG::NUM_LEVELS];
-  StringArrayProperty m_logColors[MSG::NUM_LEVELS];
-  UnsignedIntegerProperty m_statLevel;
-  UnsignedIntegerProperty m_statLevelRun;
-  UnsignedIntegerProperty m_publishLevel;
-  UnsignedIntegerProperty m_eventIDLevel;
-  IntegerProperty m_msgLimit[MSG::NUM_LEVELS];
-  BooleanProperty m_color;
-  BooleanProperty m_stats;
-  BooleanProperty m_publishStats;
-  BooleanProperty m_resetStats;
-  StringArrayProperty m_useERS[MSG::NUM_LEVELS];
-  BooleanProperty m_alwaysUseMsgStream;
-  BooleanProperty m_useErsRunningOnly;  
-  BooleanProperty m_suppress;
-  BooleanProperty m_suppressRunningOnly;
-  BooleanProperty m_forceOutputLevel;
-  
-  /* Message colors */
-  std::string m_logColorCodes[MSG::NUM_LEVELS];
-  std::string colTrans(std::string, int);
-  ColorMap m_colMap;
-
-  /* Message counting */
-  struct msgAry { int msg[MSG::NUM_LEVELS]; };
-  std::map<std::string, msgAry> m_sourceMap;      ///< Current message counting per source
-  std::map<std::string, msgAry> m_sourceMapTotal; ///< Total message counting per source
-  int m_msgCount[MSG::NUM_LEVELS];                ///< Message counting per level
-  MsgCountMap m_msgCountMap;                      ///< Message counting per message
-  TH1I* m_msgCountHist;                           ///< Message counting per level histogram
-  TH2I* m_msgCountSrcHist;                        ///< Message counting per message source
-
-  /* Update handlers */
-  void initColors(Property& prop);
-  void setupColors(Property& prop);
-  void setupLimits(Property& prop);
-  void setupThreshold(Property& prop);
-  void setupSuppression(Property& prop);
-  
-  unsigned int msgHash(const Message& msg);   ///< Hash of message (for log. suppression)
-  void resetMsgStats();                       ///< Reset message statistics
-  void reportMsgStats(uint statLevel, bool total=false);        ///< Report message statistics
-  void setOutputLevelViaJobOptSvc();          ///< Change OutputLevel properties in JobOptionsSvc
-  void bookHistograms();                      ///< Book histograms for message statistics
-  bool passErsFilter(const std::string& source, const std::vector<std::string>& filter);  ///< Source passes ERS filter?
+  //////////////////////////////////////////////////////////////////////
+  // Properties
+  //////////////////////////////////////////////////////////////////////
+  Gaudi::Property<std::string> m_defaultFormat{this, "Format", Message::getDefaultFormat(),
+                                               "Default message format"};
+  Gaudi::Property<std::string> m_ersFormat{this, "ErsFormat", Message::getDefaultFormat(),
+                                           "ERS message format"};
+  Gaudi::Property<std::string> m_defaultTimeFormat{
+      this, "timeFormat", Message::getDefaultTimeFormat(), "Message time format"};
+  Gaudi::Property<bool> m_stats{this, "showStats", false, "Show message statistics"};
+  Gaudi::Property<unsigned int> m_statLevel{this, "statLevel", 0,
+                                            "Show total message statistics for >= level"};
+  Gaudi::Property<unsigned int> m_statLevelRun{this, "statLevelRun", 0,
+                                               "Show per-run statistics for messages >= level"};
+  Gaudi::Property<bool> m_resetStats{this, "resetStatsAtBeginRun", false,
+                                     "Reset message statistics at BeginRun"};
+  Gaudi::Property<unsigned int> m_eventIDLevel{this, "printEventIDLevel", MSG::NIL,
+                                               "Print event ID for this and higher message levels"};
+  Gaudi::Property<bool> m_color{this, "useColors", false,
+                                "Colors are not supported by TrigMessageSvc"};
+  Gaudi::Property<bool> m_suppress{this, "enableSuppression", false, "Enable message suppression"};
+  Gaudi::Property<bool> m_suppressRunningOnly{this, "suppressRunningOnly", true,
+                                              "Use message suppression only during RUNNING state"};
+
+  std::array<Gaudi::Property<std::vector<std::string>>, MSG::NUM_LEVELS> m_thresholdProp{
+      {{/*ignored*/},
+       {this, "setVerbose"},
+       {this, "setDebug"},
+       {this, "setInfo"},
+       {this, "setWarning"},
+       {this, "setError"},
+       {this, "setFatal"},
+       {this, "setAlways"}}};
+
+  std::array<Gaudi::Property<int>, MSG::NUM_LEVELS> m_msgLimit{{{this, "defaultLimit", 500},
+                                                                {this, "verboseLimit", 500},
+                                                                {this, "debugLimit", 500},
+                                                                {this, "infoLimit", 500},
+                                                                {this, "warningLimit", 500},
+                                                                {this, "errorLimit", 500},
+                                                                {this, "fatalLimit", 500},
+                                                                {this, "alwaysLimit", 0}}};
+
+  /**
+   * Special properties to control output to ERS of individual sources.
+   * The syntax is as follows (these are NOT regular expressions):
+   *
+   * useErsFatal = []                       # forward none (default)
+   * useErsFatal = ['*']                    # forward all
+   * useErsFatal = ['CoreDumpSvc','MyAlg']  # forward these sources
+   * useErsFatal = ['*','!MyAlg']           # forward all except MyAlg
+   */
+  std::array<Gaudi::Property<std::vector<std::string>>, MSG::NUM_LEVELS> m_useERS{
+      {{/*ignored*/},
+       {this, "useErsVerbose", {}},
+       {this, "useErsDebug", {}},
+       {this, "useErsInfo", {}},
+       {this, "useErsWarning", {}},
+       {this, "useErsError", {}},
+       {this, "useErsFatal", {}},
+       {this, "useErsAlways", {}}}};
+
+  //////////////////////////////////////////////////////////////////////
+  // Private members
+  //////////////////////////////////////////////////////////////////////
+  std::ostream* m_defaultStream = &std::cout; ///< Pointer to the output stream.
+  ThresholdMap m_thresholdMap;                ///< Output level threshold map
+
+  /// Private helper class to keep the count of messages of a type (MSG::LEVEL).
+  struct MsgAry final {
+    /// Internal array of counters.
+    std::array<int, MSG::NUM_LEVELS> msg = {{0}};
+    /// Default constructor.
+    MsgAry() = default;
+  };
+
+  std::map<std::string, MsgAry> m_sourceMap;     ///< counts per source
+  std::array<int, MSG::NUM_LEVELS> m_msgCount;   ///< counts per level
+  std::map<size_t, unsigned int> m_msgHashCount; ///< counts per message hash
+
+  bool m_running{false};    ///< are we in running state?
+  bool m_doSuppress{false}; ///< is suppression currently enabled?
+
+  mutable std::recursive_mutex m_reportMutex;       ///< mutex for printing
+  mutable std::recursive_mutex m_thresholdMapMutex; /// (@see MsgStream::doOutput).
+
+  void setupLimits(Gaudi::Details::PropertyBase& prop);
+  void setupThreshold(Gaudi::Details::PropertyBase& prop);
+  bool passErsFilter(const std::string& source, const std::vector<std::string>& filter) const;
+  void i_reportMessage(const Message& msg, int outputLevel);
+  void i_reportERS(const Message& msg) const;
 };
 
 #endif
diff --git a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx
index 85a1766f21a13aea199ffccd7a64a2cb56eb65de..cf57b1ea47040566ae525ecdfc66b1c34d1027b5 100644
--- a/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx
+++ b/HLT/Trigger/TrigControl/TrigServices/src/TrigMonTHistSvc.cxx
@@ -1,11 +1,12 @@
 /*
-  Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
 */
 
 
 #include "GaudiKernel/ISvcLocator.h"
 
 #include "AthenaKernel/errorcheck.h"
+#include "CxxUtils/checker_macros.h"
 #include "TrigMonTHistSvc.h"
 #include "TrigMonitorBase/TrigLockedHist.h"
 
@@ -52,7 +53,7 @@ StatusCode TrigMonTHistSvc::queryInterface(const InterfaceID & riid,
 }
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-StatusCode TrigMonTHistSvc::initialize() {
+StatusCode TrigMonTHistSvc::initialize ATLAS_NOT_THREAD_SAFE() {
 
   CHECK(THistSvcHLT::initialize());
   CHECK(setProperties());