diff --git a/algo/ca/core/CMakeLists.txt b/algo/ca/core/CMakeLists.txt
index 78756d5be14edbead64bf53208b1af5c71f2d082..0f73dd62989789977811ea4b2e63a0d8dc3ed79a 100644
--- a/algo/ca/core/CMakeLists.txt
+++ b/algo/ca/core/CMakeLists.txt
@@ -82,6 +82,7 @@ install(
     pars/CaSearchWindow.h
     pars/CaStation.h
     pars/CaStationInitializer.h
+    utils/CaTrackingMonitor.h
     utils/CaEnumArray.h
     utils/CaMonitor.h
     utils/CaObjectInitController.h
diff --git a/algo/ca/core/utils/CaEnumArray.h b/algo/ca/core/utils/CaEnumArray.h
index bcf5a270e6b916f668d156460775f281cb2531a5..a34409ae4478acded96b7808a1c408359a9166cf 100644
--- a/algo/ca/core/utils/CaEnumArray.h
+++ b/algo/ca/core/utils/CaEnumArray.h
@@ -13,6 +13,15 @@
 
 namespace cbm::algo::ca
 {
+  /// \enum  EDummy
+  /// \brief Dummy enum, representing an array with zero elements
+  ///
+  /// This enumeration is to be used as the default template parameter
+  enum class EDummy
+  {
+    kEND
+  };
+
   /// \class cbm::algo::ca::EnumArray
   /// \brief Class of arrays, which can be accessed by an enum class entry as an index
   /// \note  The enum-array must contain an entry kEND, which represents the number of the enumeration entries and
diff --git a/algo/ca/core/utils/CaMonitor.h b/algo/ca/core/utils/CaMonitor.h
index 749f11fc826f1320713742d2dd03d86ac7de726f..aa88a10558bb98006021c28b003b8eb4778b1e20 100644
--- a/algo/ca/core/utils/CaMonitor.h
+++ b/algo/ca/core/utils/CaMonitor.h
@@ -9,66 +9,127 @@
 
 #pragma once  // include this header only once per compilation unit
 
+#include <algorithm>
 #include <iomanip>
 #include <sstream>
 #include <string>
+#include <string_view>
+#include <vector>
 
 #include "CaEnumArray.h"
-#include "CaTimer.h"
+#include "CaMonitorData.h"
 
 namespace cbm::algo::ca
 {
   /// \class  Monitor
   /// \brief  Monitor class for the CA tracking
-  /// \tparam EMonitorKey  A enum class, containing keys for monitorables
+  /// \tparam ECounterKey  A enum class, containing keys for monitorables
+  /// \tparam ETimerKey    A enum class, containing keys for timers
   ///
-  template<class EMonitorKey>
+  template<class ECounterKey, class ETimerKey = EDummy>
   class Monitor {
   public:
-    /// \brief Alias to array, indexed by Monitorable enumeration
+    /// \brief Alias to array, indexed by the monitorable enumeration
     template<typename T>
-    using MonitorableArr_t = EnumArray<EMonitorKey, T>;
+    using CounterArray = EnumArray<ECounterKey, T>;
+
+    /// \brief Alias to array, indexed by the timer enumeration
+    template<typename T>
+    using TimerArray = EnumArray<ETimerKey, T>;
 
     /// \brief Constructor
     /// \param name Name of monitor
-    Monitor(const std::string& name) : fsName(name) {}
+    Monitor(std::string_view name) : fsName(name) {}
+
+    /// \brief Default constructor
+    Monitor() = default;
+
+    /// \brief Destructor
+    ~Monitor() = default;
+
+    /// \brief Copy constructor
+    Monitor(const Monitor&) = delete;
+
+    /// \brief Move constructor
+    Monitor(Monitor&&) = delete;
 
-    /// \brief Gets key name
-    /// \param key Monitorable key
-    const std::string& GetKeyName(EMonitorKey key) const { return faKeyNames[key]; }
+    /// \brief Copy assignment operator
+    Monitor& operator=(const Monitor&) = delete;
+
+    /// \brief Move assignment operator
+    Monitor& operator=(Monitor&&) = delete;
+
+    /// \brief Gets counter name
+    /// \param key Counter key
+    const std::string& GetCounterName(ECounterKey key) const { return faCounterNames[key]; }
 
     /// \brief Gets counter value
     /// \param key
-    int GetValue(EMonitorKey key) const { return faKeyCounters[key]; }
+    int GetCounterValue(ECounterKey key) const { return fMonitorData.GetCounterValue(key); }
+
+    /// \brief Gets monitor data
+    const MonitorData<ECounterKey, ETimerKey>& GetMonitorData() const { return fMonitorData; }
+
+    /// \brief Gets name of the monitor
+    const std::string& GetName() const { return fsName; }
+
+    /// \brief Gets timer
+    /// \param key Timer key
+    const Timer& GetTimer(ETimerKey key) const { return fMonitorData.GetTimer(); }
+
+    /// \brief Gets timer name
+    /// \param key Timer key
+    const std::string& GetTimerName(ETimerKey key) const { return faTimerNames[key]; }
 
     /// \brief Increments key counter by 1
-    /// \param key Monitorable key
-    void Increment(EMonitorKey key) { ++faKeyCounters[key]; };
+    /// \param key Counter key
+    void IncrementCounter(ECounterKey key) { fMonitorData.IncrementCounter(key); };
 
     /// \brief Increments key counter by a number
-    /// \param key  Monitorable key
+    /// \param key  Counter key
     /// \param num  Number to add
-    void Increment(EMonitorKey key, int num) { faKeyCounters[key] += num; }
+    void IncrementCounter(ECounterKey key, int num) { fMonitorData.IncrementCounter(key, num); }
 
     /// \brief Resets the counters
-    void Reset() { faKeyCounters.fill(0); }
+    void Reset() { fMonitorData.Reset(); }
 
-    /// \brief Sets keys of monitorables, which are used as denominators for ratios
+    /// \brief Sets keys of counters, which are used as denominators for ratios
     /// \param vKeys Vector of keys
-    void SetRatioKeys(const std::vector<EMonitorKey>& vKeys) { fvRatioKeys = vKeys; }
+    void SetRatioKeys(const std::vector<ECounterKey>& vKeys) { fvCounterRatioKeys = vKeys; }
+
+    /// \brief Sets name of counter
+    /// \param name  Name of counter
+    void SetCounterName(ECounterKey key, std::string_view name) { faCounterNames[key] = name; }
+
+    /// \brief Sets monitor data
+    /// \param data  The MonitorData class objet
+    void SetMonitorData(const MonitorData<ECounterKey, ETimerKey>& data) { fMonitorData = data; }
+
+    /// \brief Sets name of the monitor
+    /// \param name  Name of the monitor
+    void SetName(std::string_view name) { fsName = name; }
+
+    /// \brief Sets name of the timer
+    /// \param name  Name of the timer
+    void SetTimerName(ETimerKey key, std::string_view name) { faTimerNames[key] = name; }
 
-    /// \brief Sets name of key
-    /// \param name  Name of monitoralble
-    void SetKeyName(EMonitorKey key, const char* name) { faKeyNames[key] = name; }
+    /// \brief Starts timer
+    /// \param key  Timer key
+    void StartTimer(ETimerKey key) { fMonitorData.StartTimer(key); }
+
+    /// \brief Stops timer
+    /// \param key  Timer key
+    void StopTimer(ETimerKey key) { fMonitorData.StopTimer(key); }
 
     /// \brief Prints counters summary to string
     std::string ToString() const;
 
   private:
-    std::vector<EMonitorKey> fvRatioKeys {};      ///< List of keys, which are used as denominators in ratios
-    std::string fsName;                           ///< Name of the monitor
-    MonitorableArr_t<std::string> faKeyNames {};  ///< Names of keys
-    MonitorableArr_t<int> faKeyCounters {};       ///< Counters of keys
+    MonitorData<ECounterKey, ETimerKey> fMonitorData;  ///< Monitor data
+    TimerArray<std::string> faTimerNames {};           ///< Array of timer names
+    CounterArray<std::string> faCounterNames {};       ///< Array of counter names
+    std::vector<ECounterKey> fvCounterRatioKeys {};    ///< List of keys, which are used as denominators in ratios
+    std::string fsName;                                ///< Name of the monitor
   };
 
 
@@ -78,8 +139,8 @@ namespace cbm::algo::ca
 
   // ---------------------------------------------------------------------------------------------------------------------
   //
-  template<class EMonitorKey>
-  std::string Monitor<EMonitorKey>::ToString() const
+  template<class ECounterKey, class ETimerKey>
+  std::string Monitor<ECounterKey, ETimerKey>::ToString() const
   {
     using std::left;
     using std::right;
@@ -87,20 +148,42 @@ namespace cbm::algo::ca
     using std::setw;
     std::stringstream msg;
     constexpr size_t width = 24;
-    size_t fillWidth       = (width + 2) * (1 + fvRatioKeys.size());
+    size_t fillWidth       = (width + 2) * (1 + fvCounterRatioKeys.size());
     msg << "----- Monitor: " << fsName << ' ' << setw(fillWidth - fsName.size() - 16) << setfill('-') << '-' << '\n';
     msg << setfill(' ');
+
+    if constexpr (!std::is_same_v<ETimerKey, EDummy>) {
+      msg << "----- Timers:\n";
+      msg << setw(width) << "Name" << ' ';
+      msg << setw(width) << "N Calls" << ' ';
+      msg << setw(width) << "Average [ns]" << ' ';
+      msg << setw(width) << "Min [ns]" << ' ';
+      msg << setw(width) << "Max [ns]" << ' ';
+      msg << setw(width) << "Total [ns]" << '\n';
+      for (int iKey = 0; iKey < fMonitorData.GetNofTimers(); ++iKey) {
+        const auto& timer = fMonitorData.GetTimer(static_cast<ETimerKey>(iKey));
+        msg << setw(width) << faTimerNames[iKey] << ' ';
+        msg << setw(width) << timer.GetNofCalls() << ' ';
+        msg << setw(width) << timer.GetAverage() << ' ';
+        msg << setw(width) << timer.GetMin() << ' ';
+        msg << setw(width) << timer.GetMax() << ' ';
+        msg << setw(width) << timer.GetTotal() << '\n';
+      }
+    }
+
+    msg << "----- Counters:\n";
     msg << setw(width) << left << "Key" << ' ';
     msg << setw(width) << left << "Total" << ' ';
-    for (auto key : fvRatioKeys) {
-      msg << setw(width) << left << std::string("per ") + faKeyNames[key] << ' ';
+    for (auto key : fvCounterRatioKeys) {
+      msg << setw(width) << left << std::string("per ") + faCounterNames[key] << ' ';
     }
     msg << '\n';
-    for (int iKey = 0; iKey < static_cast<int>(EMonitorKey::kEND); ++iKey) {
-      msg << setw(width) << left << faKeyNames[iKey] << ' ';
-      msg << setw(width) << right << faKeyCounters[iKey] << ' ';
-      for (auto keyDen : fvRatioKeys) {
-        auto ratio = static_cast<double>(faKeyCounters[iKey]) / faKeyCounters[keyDen];
+    for (int iKey = 0; iKey < fMonitorData.GetNofCounters(); ++iKey) {
+      auto counterValue = fMonitorData.GetCounterValue(static_cast<ECounterKey>(iKey));
+      msg << setw(width) << left << faCounterNames[iKey] << ' ';
+      msg << setw(width) << right << counterValue << ' ';
+      for (auto keyDen : fvCounterRatioKeys) {
+        auto ratio = static_cast<double>(counterValue) / fMonitorData.GetCounterValue(keyDen);
         msg << setw(width) << right << ratio << ' ';
       }
       msg << '\n';
diff --git a/algo/ca/core/utils/CaMonitorData.h b/algo/ca/core/utils/CaMonitorData.h
new file mode 100644
index 0000000000000000000000000000000000000000..20f7270c9be1a61558e4036b7227da19b3851e70
--- /dev/null
+++ b/algo/ca/core/utils/CaMonitorData.h
@@ -0,0 +1,107 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CaMonitorData.h
+/// \brief  A block of data for cbm::algo::ca::Monitor
+/// \since  19.10.2023
+/// \author S.Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+#include "CaEnumArray.h"
+#include "CaTimer.h"
+
+namespace cbm::algo::ca
+{
+  /// \class MonitorData
+  /// \brief Monitor data block
+  /// \tparam ECounterKey  A enum class, containing keys for monitorables
+  /// \tparam ETimerKey    A enum class, containing keys for timers
+  ///
+  template<class ECounterKey, class ETimerKey>
+  class MonitorData {
+  public:
+    /// \brief Alias to array, indexed by the counter enumeration
+    template<typename T>
+    using CounterArray = EnumArray<ECounterKey, T>;
+
+    /// \brief Alias to array, indexed by the timer enumeration
+    template<typename T>
+    using TimerArray = EnumArray<ETimerKey, T>;
+
+    /// \brief Default constructor
+    MonitorData() = default;
+
+    /// \brief Copy constructor
+    MonitorData(const MonitorData&) = default;
+
+    /// \brief Move constructor
+    MonitorData(MonitorData&&) = default;
+
+    /// \brief Destructor
+    ~MonitorData() = default;
+
+    /// \brief Copy assignment operator
+    MonitorData& operator=(const MonitorData&) = default;
+
+    /// \brief Move assignment operator
+    MonitorData& operator=(MonitorData&&) = default;
+
+    /// \brief Gets counter value
+    /// \param key
+    int GetCounterValue(ECounterKey key) const { return faCounters[key]; }
+
+    /// \brief Gets number of counters
+    int GetNofCounters() const { return static_cast<int>(ECounterKey::kEND); }
+
+    /// \brief Gets number of timers
+    int GetNofTimers() const { return static_cast<int>(ETimerKey::kEND); }
+
+    /// \brief Gets timer
+    /// \param key Timer key
+    template<typename T>
+    const Timer& GetTimer(ETimerKey key) const
+    {
+      return faTimers[key];
+    }
+
+    /// \brief Increments key counter by 1
+    /// \param key Counter key
+    void IncrementCounter(ECounterKey key) { ++faCounters[key]; };
+
+    /// \brief Increments key counter by a number
+    /// \param key  Counter key
+    /// \param num  Number to add
+    void IncrementCounter(ECounterKey key, int num) { faCounters[key] += num; }
+
+    /// \brief Resets all the counters and timers
+    void Reset();
+
+    /// \brief Starts timer
+    /// \param key  Timer key
+    void StartTimer(ETimerKey key) { faTimers[key].Start(); }
+
+    /// \brief Stops timer
+    /// \param key  Timer key
+    void StopTimer(ETimerKey key) { faTimers[key].Stop(); }
+
+  private:
+    TimerArray<Timer> faTimers {};    ///< Array of timers
+    CounterArray<int> faCounters {};  ///< Array of counters
+  };
+
+
+  // *****************************************
+  // **  Template function implementations  **
+  // *****************************************
+
+  // ---------------------------------------------------------------------------------------------------------------------
+  //
+  template<class ECounterKey, class ETimerKey>
+  inline void MonitorData<ECounterKey, ETimerKey>::Reset()
+  {
+    faCounters.fill(0);
+    std::for_each(faTimers.begin(), faTimers.end(), [](auto& timer) { timer.Reset(); });
+  }
+}  // namespace cbm::algo::ca
diff --git a/algo/ca/core/utils/CaTimer.cxx b/algo/ca/core/utils/CaTimer.cxx
index 84cc02a6e41b403292f1d2f8e07260a85040b00d..d55c2e62ae4e75a5d0958c974711e8dc35e3da53 100644
--- a/algo/ca/core/utils/CaTimer.cxx
+++ b/algo/ca/core/utils/CaTimer.cxx
@@ -23,7 +23,7 @@ std::string Timer::ToString() const
   using std::setw;
 
   std::stringstream msg;
-  msg << left << setw(25) << fName << right << " min = " << setw(15) << fMin << " ns, max = " << setw(15) << fMax
-      << " ns, average = " << setw(15) << GetAverage() << " ns, total = " << fTotal << " ns, N calls = " << fNofCalls;
+  msg << "min = " << setw(15) << fMin << " ns, max = " << setw(15) << fMax << " ns, average = " << setw(15)
+      << GetAverage() << " ns, total = " << fTotal << " ns, N calls = " << fNofCalls;
   return msg.str();
 }
diff --git a/algo/ca/core/utils/CaTimer.h b/algo/ca/core/utils/CaTimer.h
index 49f8be69e7411236645059d1ab85121c26018a79..25f9dac591c0f2143caeb7522b2e611cb1e88e93 100644
--- a/algo/ca/core/utils/CaTimer.h
+++ b/algo/ca/core/utils/CaTimer.h
@@ -53,24 +53,21 @@ namespace cbm::algo::ca
     /// \brief Gets time of the shortest call [ns]
     DurationCount GetMin() const { return fMin; }
 
+    /// \brief Gets number of calls
+    int GetNofCalls() const { return fNofCalls; }
+
     /// \brief Gets index of the longest call
     int GetMaxCallIndex() const { return fMaxCallIndex; }
 
     /// \brief Gets index of the longest call
     int GetMinCallIndex() const { return fMinCallIndex; }
 
-    /// \brief Gets name
-    const std::string& GetName() const { return fName; }
-
     /// \brief Gets total time [ns]
     DurationCount GetTotal() const;
 
     /// \brief Resets the timer
     void Reset();
 
-    /// \brief Sets name
-    void SetName(const std::string& name) { fName = name; }
-
     /// \brief Starts the timer
     void Start() { fStart = Clock::now(); }
 
@@ -81,7 +78,6 @@ namespace cbm::algo::ca
     std::string ToString() const;
 
   private:
-    std::string fName    = "no name";  ///< Name of the timer
     TimePoint fStart     = TimePoint();
     DurationCount fMin   = std::numeric_limits<DurationCount>::max();  ///< Minimal time period
     DurationCount fMax   = std::numeric_limits<DurationCount>::min();  ///< Maximal time period
diff --git a/algo/ca/core/utils/CaTrackingMonitor.h b/algo/ca/core/utils/CaTrackingMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..49b522c9c3cebe9c55a2c067af9a4de437115e4f
--- /dev/null
+++ b/algo/ca/core/utils/CaTrackingMonitor.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Sergei Zharko [committer] */
+
+/// \file   CaTrackingMonitor.h
+/// \brief  Monitor specification for the tracking algorithm
+/// \since  19.10.2023
+/// \author S.Zharko <s.zharko@gsi.de>
+
+#pragma once
+
+#include "CaMonitor.h"
+
+namespace cbm::algo::ca
+{
+  /// \enum  ECounter
+  /// \brief Counter keys for the CA algo monitor
+  enum class ECounter
+  {
+    RecoTrack,  ///< number of reconstructed tracks
+    RecoHit,    ///< number of reconstructed hits
+    kEND
+  };
+
+  /// \enum  ETimer
+  /// \brief Timer keys for the CA algo monitor
+  enum class ETimer
+  {
+    Tracking,
+    TrackFinder,
+    TrackFitter,
+    kEND
+  };
+
+  using TrackingMonitor = Monitor<ECounter, ETimer>;
+}  // namespace cbm::algo::ca
diff --git a/reco/L1/CbmCaMCModule.cxx b/reco/L1/CbmCaMCModule.cxx
index eeb8fc81c5c2a4356b5f70021e71075ec8dc3ec6..71c58aa83fd8d21a46cf9352c643cc8e6e6abd05 100644
--- a/reco/L1/CbmCaMCModule.cxx
+++ b/reco/L1/CbmCaMCModule.cxx
@@ -118,15 +118,15 @@ try {
   this->CheckInit();
 
   // Init monitor
-  fMonitor.SetKeyName(EMonitorKey::kMcTrack, "N MC tracks");
-  fMonitor.SetKeyName(EMonitorKey::kMcTrackReconstructable, "N MC tracks rec-able");
-  fMonitor.SetKeyName(EMonitorKey::kMcPoint, "N MC points");
-  fMonitor.SetKeyName(EMonitorKey::kRecoNevents, "N reco events");
-  fMonitor.SetKeyName(EMonitorKey::kMissedMatchesMvd, "N missed MVD matches");
-  fMonitor.SetKeyName(EMonitorKey::kMissedMatchesSts, "N missed STS matches");
-  fMonitor.SetKeyName(EMonitorKey::kMissedMatchesMuch, "N missed MuCh matches");
-  fMonitor.SetKeyName(EMonitorKey::kMissedMatchesTrd, "N missed TRD matches");
-  fMonitor.SetKeyName(EMonitorKey::kMissedMatchesTof, "N missed TOF matches");
+  fMonitor.SetCounterName(EMonitorKey::kMcTrack, "N MC tracks");
+  fMonitor.SetCounterName(EMonitorKey::kMcTrackReconstructable, "N MC tracks rec-able");
+  fMonitor.SetCounterName(EMonitorKey::kMcPoint, "N MC points");
+  fMonitor.SetCounterName(EMonitorKey::kRecoNevents, "N reco events");
+  fMonitor.SetCounterName(EMonitorKey::kMissedMatchesMvd, "N missed MVD matches");
+  fMonitor.SetCounterName(EMonitorKey::kMissedMatchesSts, "N missed STS matches");
+  fMonitor.SetCounterName(EMonitorKey::kMissedMatchesMuch, "N missed MuCh matches");
+  fMonitor.SetCounterName(EMonitorKey::kMissedMatchesTrd, "N missed TRD matches");
+  fMonitor.SetCounterName(EMonitorKey::kMissedMatchesTof, "N missed TOF matches");
   fMonitor.SetRatioKeys({EMonitorKey::kRecoNevents});
 
 
@@ -165,8 +165,8 @@ void MCModule::InitEvent(CbmEvent* /*pEvent*/)
   fpMCData->Clear();
   this->ReadMCTracks();
   this->ReadMCPoints();
-  fMonitor.Increment(EMonitorKey::kMcTrack, fpMCData->GetNofPoints());
-  fMonitor.Increment(EMonitorKey::kMcPoint, fpMCData->GetNofTracks());
+  fMonitor.IncrementCounter(EMonitorKey::kMcTrack, fpMCData->GetNofPoints());
+  fMonitor.IncrementCounter(EMonitorKey::kMcPoint, fpMCData->GetNofTracks());
 
   // Prepare tracks: set point indexes and redefine indexes from external to internal containers
   for (auto& aTrk : fpMCData->GetTrackContainer()) {
@@ -174,7 +174,7 @@ void MCModule::InitEvent(CbmEvent* /*pEvent*/)
       [&](const int& iPl, const int& iPr) { return fpMCData->GetPoint(iPl).GetZ() < fpMCData->GetPoint(iPr).GetZ(); });
   }
 
-  fMonitor.Increment(EMonitorKey::kRecoNevents);
+  fMonitor.IncrementCounter(EMonitorKey::kRecoNevents);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -246,7 +246,7 @@ void MCModule::MatchRecoAndMC()
   this->MatchRecoAndMCTracks();
   this->InitTrackInfo();
   for (const auto& trkMC : fpMCData->GetTrackContainer()) {
-    if (trkMC.IsReconstructable()) { fMonitor.Increment(EMonitorKey::kMcTrackReconstructable); }
+    if (trkMC.IsReconstructable()) { fMonitor.IncrementCounter(EMonitorKey::kMcTrackReconstructable); }
   }
 }
 
diff --git a/reco/L1/CbmCaMCModule.h b/reco/L1/CbmCaMCModule.h
index 8a289b8b7594f6bb13ce34893d2ce0d482f79d40..7d1462a14d7d45fca822ea17caa6075be3a31c8e 100644
--- a/reco/L1/CbmCaMCModule.h
+++ b/reco/L1/CbmCaMCModule.h
@@ -280,18 +280,18 @@ namespace cbm::ca
     const auto* pHitMatch = dynamic_cast<CbmMatch*>(fvpBrHitMatches[DetID]->At(iHitExt));
     if (!pHitMatch) {
       LOG(warn) << "Hit match with index " << iHitExt << " is missing for " << kDetName[DetID];
-      if constexpr (ca::EDetectorID::kMvd == DetID) { fMonitor.Increment(EMonitorKey::kMissedMatchesMvd); }
+      if constexpr (ca::EDetectorID::kMvd == DetID) { fMonitor.IncrementCounter(EMonitorKey::kMissedMatchesMvd); }
       else if constexpr (ca::EDetectorID::kSts == DetID) {
-        fMonitor.Increment(EMonitorKey::kMissedMatchesSts);
+        fMonitor.IncrementCounter(EMonitorKey::kMissedMatchesSts);
       }
       else if constexpr (ca::EDetectorID::kMuch == DetID) {
-        fMonitor.Increment(EMonitorKey::kMissedMatchesMuch);
+        fMonitor.IncrementCounter(EMonitorKey::kMissedMatchesMuch);
       }
       else if constexpr (ca::EDetectorID::kTrd == DetID) {
-        fMonitor.Increment(EMonitorKey::kMissedMatchesTrd);
+        fMonitor.IncrementCounter(EMonitorKey::kMissedMatchesTrd);
       }
       else if constexpr (ca::EDetectorID::kTof == DetID) {
-        fMonitor.Increment(EMonitorKey::kMissedMatchesTof);
+        fMonitor.IncrementCounter(EMonitorKey::kMissedMatchesTof);
       }
       return std::tuple(iPoint, vPoints);
     }
diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx
index 25a31f9f4c11765f111ba603da4e6d6ea879a957..917c25f2f39c78f9780e22f07f368a17a4e36fb3 100644
--- a/reco/L1/CbmL1.cxx
+++ b/reco/L1/CbmL1.cxx
@@ -700,15 +700,15 @@ InitStatus CbmL1::Init()
   DumpMaterialToFile("L1material.root");
 
   // Initialize monitor
-  fMonitor.SetKeyName(EMonitorKey::kEvent, "N events");
-  fMonitor.SetKeyName(EMonitorKey::kRecoTrack, "N reco tracks");
-  fMonitor.SetKeyName(EMonitorKey::kRecoHit, "N hits");
-  fMonitor.SetKeyName(EMonitorKey::kGhostTrack, "N ghosts");
-  fMonitor.SetKeyName(EMonitorKey::kDiscardedHitMvd, "N discarded hits in MVD");
-  fMonitor.SetKeyName(EMonitorKey::kDiscardedHitSts, "N discarded hits in STS");
-  fMonitor.SetKeyName(EMonitorKey::kDiscardedHitMuch, "N discarded hits in MUCH");
-  fMonitor.SetKeyName(EMonitorKey::kDiscardedHitTrd, "N discarded hits in TRD");
-  fMonitor.SetKeyName(EMonitorKey::kDiscardedHitTof, "N discarded hits in TOF");
+  fMonitor.SetCounterName(EMonitorKey::kEvent, "N events");
+  fMonitor.SetCounterName(EMonitorKey::kRecoTrack, "N reco tracks");
+  fMonitor.SetCounterName(EMonitorKey::kRecoHit, "N hits");
+  fMonitor.SetCounterName(EMonitorKey::kGhostTrack, "N ghosts");
+  fMonitor.SetCounterName(EMonitorKey::kDiscardedHitMvd, "N discarded hits in MVD");
+  fMonitor.SetCounterName(EMonitorKey::kDiscardedHitSts, "N discarded hits in STS");
+  fMonitor.SetCounterName(EMonitorKey::kDiscardedHitMuch, "N discarded hits in MUCH");
+  fMonitor.SetCounterName(EMonitorKey::kDiscardedHitTrd, "N discarded hits in TRD");
+  fMonitor.SetCounterName(EMonitorKey::kDiscardedHitTof, "N discarded hits in TOF");
   fMonitor.SetRatioKeys({EMonitorKey::kEvent, EMonitorKey::kRecoTrack});
   fMonitor.Reset();
 
@@ -820,10 +820,10 @@ void CbmL1::Reconstruct(CbmEvent* event)
       t.Hits.push_back(cbmHitID);
     }
     fvRecoTracks.push_back(t);
-    fMonitor.Increment(EMonitorKey::kRecoHit, it->fNofHits);
+    fMonitor.IncrementCounter(EMonitorKey::kRecoHit, it->fNofHits);
   }
 
-  fMonitor.Increment(EMonitorKey::kRecoTrack, fvRecoTracks.size());
+  fMonitor.IncrementCounter(EMonitorKey::kRecoTrack, fvRecoTracks.size());
 
   LOG(info) << "CA Track Finder: " << fpAlgo->fCaRecoTime << " s/sub-ts";
   LOG(info) << GetName() << ": " << fpAlgo->fRecoTimer.ToString();
@@ -900,7 +900,7 @@ void CbmL1::Reconstruct(CbmEvent* event)
   }
 
   ++fEventNo;
-  fMonitor.Increment(EMonitorKey::kEvent);
+  fMonitor.IncrementCounter(EMonitorKey::kEvent);
 }
 
 // -----   Finish CbmStsFitPerformanceTask task   -----------------------------
diff --git a/reco/L1/CbmL1.h b/reco/L1/CbmL1.h
index f430443a2a4d4cda4884b3f744a62367e4f3ca35..ec4bba1492e50770cb36fca8a7530ba89cdabeec 100644
--- a/reco/L1/CbmL1.h
+++ b/reco/L1/CbmL1.h
@@ -273,7 +273,7 @@ public:
     kEND
   };
 
-  ca::Monitor<EMonitorKey> fMonitor = {"CA Tracking"};  ///< Tracking monitor
+  ca::Monitor<EMonitorKey> fMonitor = {"CbmL1 Monitor"};  ///< Tracking monitor
 
 
   //   void SetTrackingLevel( Int_t iLevel ){ fTrackingLevel = iLevel; }
diff --git a/reco/L1/CbmL1Performance.cxx b/reco/L1/CbmL1Performance.cxx
index 51d507a1bb582609dba313dd20c38a123544aaaa..8cf2daa8f5faef0d813d67a362b2944cbf257f72 100644
--- a/reco/L1/CbmL1Performance.cxx
+++ b/reco/L1/CbmL1Performance.cxx
@@ -876,7 +876,7 @@ void CbmL1::HistoPerformance()  // TODO: check if works correctly. Change vHitFa
 
     // fill ghost histos
     if (prtra->IsGhost()) {
-      fMonitor.Increment(EMonitorKey::kGhostTrack);
+      fMonitor.IncrementCounter(EMonitorKey::kGhostTrack);
       h_ghost_purity->Fill(100 * prtra->GetMaxPurity());
       if (fabs(prtra->GetQp()) > 1.e-10) {
         h_ghost_mom->Fill(prtra->GetP());
diff --git a/reco/L1/CbmL1ReadEvent.cxx b/reco/L1/CbmL1ReadEvent.cxx
index 618ccfbe3ab7bda029bad74f8e3dadffc3e24c76..c01b291e0d9dc4ffef4d9bda4037395bcaf287d0 100644
--- a/reco/L1/CbmL1ReadEvent.cxx
+++ b/reco/L1/CbmL1ReadEvent.cxx
@@ -419,7 +419,7 @@ void CbmL1::ReadEvent(CbmEvent* event)
         nMvdHits++;
       }
       else {
-        fMonitor.Increment(EMonitorKey::kDiscardedHitMvd);
+        fMonitor.IncrementCounter(EMonitorKey::kDiscardedHitMvd);
       }
     }  // for j
   }    // if fpMvdHits
@@ -487,7 +487,7 @@ void CbmL1::ReadEvent(CbmEvent* event)
         nStsHits++;
       }
       else {
-        fMonitor.Increment(EMonitorKey::kDiscardedHitSts);
+        fMonitor.IncrementCounter(EMonitorKey::kDiscardedHitSts);
       }
     }  // for j
   }    // if fpStsHits
@@ -542,7 +542,7 @@ void CbmL1::ReadEvent(CbmEvent* event)
         nMuchHits++;
       }
       else {
-        fMonitor.Increment(EMonitorKey::kDiscardedHitMuch);
+        fMonitor.IncrementCounter(EMonitorKey::kDiscardedHitMuch);
       }
 
     }  // for j
@@ -615,7 +615,7 @@ void CbmL1::ReadEvent(CbmEvent* event)
         nTrdHits++;
       }
       else {
-        fMonitor.Increment(EMonitorKey::kDiscardedHitTrd);
+        fMonitor.IncrementCounter(EMonitorKey::kDiscardedHitTrd);
       }
     }  // for fpTrdHits
   }    // read TRD hits
@@ -683,7 +683,7 @@ void CbmL1::ReadEvent(CbmEvent* event)
         nTofHits++;
       }
       else {
-        fMonitor.Increment(EMonitorKey::kDiscardedHitTof);
+        fMonitor.IncrementCounter(EMonitorKey::kDiscardedHitTof);
       }
     }  // for j
   }    // if listTofHits
diff --git a/reco/L1/L1Algo/L1Algo.cxx b/reco/L1/L1Algo/L1Algo.cxx
index 910afa8a7deb887df4eef2a1c4f404921c6c369f..88ab80bb68708160e9adbe2f1235cb20a3ff82e6 100644
--- a/reco/L1/L1Algo/L1Algo.cxx
+++ b/reco/L1/L1Algo/L1Algo.cxx
@@ -16,11 +16,29 @@ L1Algo::L1Algo()
   }
 }
 
+using cbm::algo::ca::ECounter;  // monitor counter key type
 using cbm::algo::ca::EDetectorID;
+using cbm::algo::ca::ETimer;  // monitor timer key type
 using cbm::ca::tools::Debugger;
 
-void L1Algo::Init(const TrackingMode mode) { fTrackingMode = mode; }
+// ---------------------------------------------------------------------------------------------------------------------
+//
+void L1Algo::Init(const TrackingMode mode)
+{
+  fTrackingMode = mode;
+
+  // Monitor settings
+  fMonitor.SetCounterName(ECounter::RecoTrack, "reco tracks");
+  fMonitor.SetCounterName(ECounter::RecoHit, "reco hits");
+  fMonitor.SetTimerName(ETimer::Tracking, "full tracking");
+  fMonitor.SetTimerName(ETimer::TrackFinder, "track finder");
+  fMonitor.SetTimerName(ETimer::TrackFitter, "track fitter");
+  fMonitor.SetRatioKeys({ECounter::RecoTrack});
+  fMonitor.Reset();
+}
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
 void L1Algo::Finish() { Debugger::Instance().Write(); }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -31,8 +49,6 @@ void L1Algo::ReceiveInputData(InputData&& inputData)
   fInputData = std::move(inputData);
 }
 
-
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void L1Algo::ReceiveParameters(Parameters&& parameters)
@@ -54,7 +70,6 @@ void L1Algo::ReceiveParameters(Parameters&& parameters)
 
   ca::FieldRegion::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField());
 
-  fRecoTimer.SetName("track finder + track fitter");
   fRecoTimer.Reset();
 }
 
diff --git a/reco/L1/L1Algo/L1Algo.h b/reco/L1/L1Algo/L1Algo.h
index f33bae1a6cc77f8803eb7d55afd35122bed01e17..90e91aa0698a05565f504da9eac99e819dc3d3ff 100644
--- a/reco/L1/L1Algo/L1Algo.h
+++ b/reco/L1/L1Algo/L1Algo.h
@@ -38,6 +38,7 @@ class L1AlgoDraw;
 #include "CaTimer.h"
 #include "CaTrack.h"
 #include "CaTrackParam.h"
+#include "CaTrackingMonitor.h"
 #include "CaTriplet.h"
 #include "CaVector.h"
 #include "L1CloneMerger.h"
@@ -87,6 +88,18 @@ public:
 #ifdef DRAW
   friend class L1AlgoDraw;
 #endif
+  // ***************************
+  // ** Internal enumerations **
+  // ***************************
+
+  /// TODO: Move to L1
+  enum TrackingMode
+  {
+    kSts,
+    kGlobal,
+    kMcbm
+  };
+
 
   // **********************************
   // ** Member functions declaration **
@@ -147,21 +160,21 @@ public:
   /// Gets pointer to input data object for external access
   const InputData& GetInputData() const { return fInputData; }
 
-  inline int PackIndex(const int& a, const int& b, const int& c);
+  int PackIndex(const int& a, const int& b, const int& c);
 
-  inline int UnPackIndex(const int& i, int& a, int& b, int& c);
+  int UnPackIndex(const int& i, int& a, int& b, int& c);
 
   /// \brief Sets a default particle mass for the track fit
-  /// It is used during reconstruction
-  /// for the multiple scattering and energy loss estimation
   /// \param mass Default particle mass
+  ///
+  /// The function is used during the reconstruction in order to estimate the multiple scattering and energy loss
   void SetDefaultParticleMass(float mass) { fDefaultMass = mass; }
 
-  /// Gets default particle mass
+  /// \brief  Gets default particle mass
   /// \return particle mass
   float GetDefaultParticleMass() const { return fDefaultMass; }
 
-  /// Gets default particle mass squared
+  /// \brief  Gets default particle mass squared
   /// \return particle mass squared
   float GetDefaultParticleMass2() const { return fDefaultMass * fDefaultMass; }
 
@@ -178,7 +191,7 @@ public:
                    unsigned char min_best_l, ca::Branch* new_tr);
 
 
-  /// Fits track
+  /// \brief Fits track
   /// \param t - track with hits
   /// \param T - track parameters
   /// \param dir - false - forward, true - backward
@@ -187,7 +200,7 @@ public:
   void BranchFitterFast(const ca::Branch& t, TrackParamV& T, const bool dir, const fvec qp0 = 0.,
                         const bool initParams = true);
 
-  /// Fits track. more precise than FitterFast
+  /// \brief Fits track. more precise than FitterFast
   /// \param t - track with hits
   /// \param T - track parameters
   /// \param dir - false - forward, true - backward
@@ -196,14 +209,14 @@ public:
   void BranchFitter(const ca::Branch& t, TrackParamV& T, const bool dir, const fvec qp0 = 0.,
                     const bool initParams = true);
 
-  /// Finds additional hits for already found track
+  /// \brief Finds additional hits for already found track
   /// \param t - track with hits
   /// \param T - track params
   /// \param dir - 0 - forward, 1 - backward
   /// \param qp0 - momentum for extrapolation
   void FindMoreHits(ca::Branch& t, TrackParamV& T, const bool dir, const fvec qp0 = 0.0);
 
-  /// Find additional hits for existing track
+  /// \brief  Finds additional hits for existing track
   /// \return chi2
   fscal BranchExtender(ca::Branch& t);
 
@@ -211,13 +224,6 @@ public:
   L1AlgoDraw* draw {nullptr};
 #endif
 
-  /// TODO: Move to L1
-  enum TrackingMode
-  {
-    kSts,
-    kGlobal,
-    kMcbm
-  };
 
   void Init(const TrackingMode mode);
 
@@ -238,6 +244,9 @@ public:
 
   float GetMaxInvMom() const { return fMaxInvMom[0]; }
 
+  /// \brief Gets reference to the monitor
+  const TrackingMonitor& GetMonitor() const { return fMonitor; }
+
 public:
   /// Gets number of stations before the pipe (MVD stations in CBM)
   int GetNstationsBeforePipe() const { return fNstationsBeforePipe; }
@@ -273,6 +282,8 @@ private:
   Vector<unsigned char> fvHitKeyFlags {
     "L1Algo::fvHitKeyFlags"};  ///< List of key flags: has been this hit or cluster already used
 
+  ca::TrackingMonitor fMonitor {};  ///< Tracking monitor
+
 public:
   Vector<L1HitTimeInfo> fHitTimeInfo;
 
@@ -300,6 +311,7 @@ public:
 
   ca::Timer fRecoTimer;  // TMP
 
+
   Vector<Track> fRecoTracks {"L1Algo::fRecoTracks"};       ///< reconstructed tracks
   Vector<ca::HitIndex_t> fRecoHits {"L1Algo::fRecoHits"};  ///< packed hits of reconstructed tracks
 
@@ -334,7 +346,6 @@ public:
 private:
   L1CloneMerger fCloneMerger {*this};  ///< Object of L1Algo clones merger algorithm
 
-private:
   /// =================================  DATA PART  =================================
 
   /// ----- Different parameters of CATrackFinder -----
diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx
index 96480667ea75fad1e1c4959714be1b92bec44ffc..91aea772f1b28c6b4ba1f6b0c79c3600f9aeff06 100644
--- a/reco/L1/qa/CbmCaOutputQa.cxx
+++ b/reco/L1/qa/CbmCaOutputQa.cxx
@@ -85,7 +85,7 @@ OutputQa::OutputQa(int verbose, bool isMCUsed) : CbmQaTask("CbmCaOutputQa", verb
 //
 void OutputQa::FillHistograms()
 {
-  fMonitor.Increment(EMonitorKey::kEvent);
+  fMonitor.IncrementCounter(EMonitorKey::kEvent);
 
   // ************************************************************************
   // ** Fill distributions for reconstructed tracks (including ghost ones) **
@@ -466,11 +466,11 @@ InitStatus OutputQa::InitDataBranches()
   }
 
   // Initialize monitor
-  fMonitor.SetKeyName(EMonitorKey::kEvent, "N events");
-  fMonitor.SetKeyName(EMonitorKey::kTrack, "N reco tracks");
-  fMonitor.SetKeyName(EMonitorKey::kHit, "N hits");
-  fMonitor.SetKeyName(EMonitorKey::kMcTrack, "N MC tracks");
-  fMonitor.SetKeyName(EMonitorKey::kMcPoint, "N MC points");
+  fMonitor.SetCounterName(EMonitorKey::kEvent, "N events");
+  fMonitor.SetCounterName(EMonitorKey::kTrack, "N reco tracks");
+  fMonitor.SetCounterName(EMonitorKey::kHit, "N hits");
+  fMonitor.SetCounterName(EMonitorKey::kMcTrack, "N MC tracks");
+  fMonitor.SetCounterName(EMonitorKey::kMcPoint, "N MC points");
   fMonitor.SetRatioKeys({EMonitorKey::kEvent, EMonitorKey::kTrack});
 
   return kSUCCESS;
@@ -605,7 +605,7 @@ std::map<std::string, bool> OutputQa::Check()
       aTable->SetRowName(iRow, "N ghosts");
       aTable->SetCell(iRow, 0, nGhosts);
       aTable->SetRowName(iRow + 1, "Ghost rate");
-      aTable->SetCell(iRow + 1, 0, nGhosts / fMonitor.GetValue(EMonitorKey::kTrack));
+      aTable->SetCell(iRow + 1, 0, nGhosts / fMonitor.GetCounterValue(EMonitorKey::kTrack));
     }
     LOG(info) << '\n' << aTable->ToString(3);
   }
@@ -903,8 +903,8 @@ InitStatus OutputQa::InitTimeSlice()
   nHits       = fvHits.size();
   nRecoTracks = fvRecoTracks.size();
 
-  fMonitor.Increment(EMonitorKey::kTrack, nRecoTracks);
-  fMonitor.Increment(EMonitorKey::kHit, nHits);
+  fMonitor.IncrementCounter(EMonitorKey::kTrack, nRecoTracks);
+  fMonitor.IncrementCounter(EMonitorKey::kHit, nHits);
 
   // Match tracks and points
   // Read MC tracks and points
@@ -913,8 +913,8 @@ InitStatus OutputQa::InitTimeSlice()
     nMCPoints = fMCData.GetNofPoints();
     nMCTracks = fMCData.GetNofTracks();
     fpMCModule->MatchRecoAndMC();
-    fMonitor.Increment(EMonitorKey::kMcPoint, nMCPoints);
-    fMonitor.Increment(EMonitorKey::kMcTrack, nMCTracks);
+    fMonitor.IncrementCounter(EMonitorKey::kMcPoint, nMCPoints);
+    fMonitor.IncrementCounter(EMonitorKey::kMcTrack, nMCTracks);
 
     if (fbDrawEvents && nMCPoints > std::max(0, fEvtDisplayMinNofPoints)) { DrawEvent(); }
   }