Files
ResInsight/ApplicationLibCode/Application/Tools/Telemetry/RiaOpenTelemetryManager.h
T
magnesj 3f7aee5972 #14720 Probe std::stacktrace by linking instead of trusting the feature macro
libstdc++ defines __cpp_lib_stacktrace from GCC 13 on, but the implementation
lives in libstdc++exp, which some distributions do not ship (Red Hat's
gcc-toolset among them). The header-only feature test then reports the feature
as present and the link fails with undefined references to
std::__stacktrace_impl::_S_current.

Add cmake/StdStacktrace.cmake, which probes the feature by actually linking:
first with no extra library, then with stdc++exp. The result selects the link
library through RESINSIGHT_STACKTRACE_LIBRARIES, or defines
RIA_HAS_STD_STACKTRACE=0 project-wide when neither links, so the crash handler
compiles out its stack-trace capture and logs the signal only.

RiaMainTools.cpp and RiaOpenTelemetryManager.h now honour a
RIA_HAS_STD_STACKTRACE definition from the build system and only include
<stacktrace> when the feature is enabled.

Follow-up to #14045.
2026-09-10 08:33:38 -04:00

206 lines
6.6 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QObject>
#include <atomic>
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <vector>
#include <version>
// std::stacktrace is C++23 and not usable on all toolchains. The build system
// probes it by linking and may force it off via RIA_HAS_STD_STACKTRACE=0, see
// cmake/StdStacktrace.cmake and #14045.
#ifndef RIA_HAS_STD_STACKTRACE
#if defined( __cpp_lib_stacktrace ) && __cpp_lib_stacktrace >= 202011L
#define RIA_HAS_STD_STACKTRACE 1
#else
#define RIA_HAS_STD_STACKTRACE 0
#endif
#endif
#if RIA_HAS_STD_STACKTRACE
#include <stacktrace>
#endif
class QString;
class QNetworkAccessManager;
class QTimer;
//==================================================================================================
//
// OpenTelemetry Manager for ResInsight
// Handles async telemetry reporting with privacy filtering and resilience
//
//==================================================================================================
class RiaOpenTelemetryManager : public QObject
{
public:
// Error handling
enum class TelemetryError
{
ConfigurationError,
NetworkError,
AuthenticationError,
QuotaExceeded,
PrivacyViolation,
InternalError
};
using ErrorCallback = std::function<void( TelemetryError, const QString& details )>;
// Health monitoring
struct HealthSnapshot
{
uint64_t eventsQueued{ 0 };
uint64_t eventsSent{ 0 };
uint64_t eventsDropped{ 0 };
uint64_t networkFailures{ 0 };
std::chrono::steady_clock::time_point lastSuccessfulSend;
std::chrono::steady_clock::time_point systemStartTime;
double getSuccessRate() const;
bool isHealthy() const;
};
struct HealthMetrics
{
std::atomic<uint64_t> eventsQueued{ 0 };
std::atomic<uint64_t> eventsSent{ 0 };
std::atomic<uint64_t> eventsDropped{ 0 };
std::atomic<uint64_t> networkFailures{ 0 };
std::chrono::steady_clock::time_point lastSuccessfulSend;
std::chrono::steady_clock::time_point systemStartTime;
};
static RiaOpenTelemetryManager& instance();
static QString getSystemUsername();
bool initialize();
void shutdown();
bool reinitialize();
// Event reporting
void reportEventAsync( const std::string& eventName, const std::map<std::string, std::string>& attributes );
#if RIA_HAS_STD_STACKTRACE
void reportCrash( int signalCode, const std::stacktrace& trace, const std::map<std::string, std::string>& extraAttributes = {} );
#endif
// Configuration
bool isEnabled() const;
bool isInitialized() const;
void setErrorCallback( ErrorCallback callback );
void setUsername( const std::string& username );
// Performance and memory management
void setMaxQueueSize( size_t maxEvents );
void enableBackpressure( bool enable );
void setMemoryThreshold( size_t maxMemoryMB );
size_t getCurrentQueueSize() const;
// Health monitoring
HealthSnapshot getHealthMetrics() const;
bool isHealthy() const;
void enableHealthMonitoring( bool enable );
private:
RiaOpenTelemetryManager();
~RiaOpenTelemetryManager() override;
RiaOpenTelemetryManager( const RiaOpenTelemetryManager& ) = delete;
RiaOpenTelemetryManager& operator=( const RiaOpenTelemetryManager& ) = delete;
struct Event
{
std::string name;
std::map<std::string, std::string> attributes;
std::chrono::system_clock::time_point timestamp;
Event( const std::string& eventName, const std::map<std::string, std::string>& attrs )
: name( eventName )
, attributes( attrs )
, timestamp( std::chrono::system_clock::now() )
{
}
};
// Initialization
bool initializeProvider();
bool createExporter();
void setupResourceAttributes();
// Event processing
void processEvents( bool ignoreCircuitBreaker = false );
void sendBatch( const std::vector<Event>& events );
void flushPendingEvents();
void onProcessEventTimer();
// Circuit breaker and resilience
void handleError( TelemetryError error, const QString& context );
void attemptReconnection();
bool isCircuitBreakerOpen() const;
void resetCircuitBreaker();
// Event filtering
bool isEventAllowed( const std::string& eventName ) const;
// Health monitoring
void updateHealthMetrics( bool success );
void sendHealthSpan();
// Thread safety
mutable std::mutex m_configMutex;
mutable std::mutex m_queueMutex;
std::queue<Event> m_eventQueue;
// State
std::atomic<bool> m_initialized{ false };
std::atomic<bool> m_enabled{ false };
std::atomic<bool> m_isShuttingDown{ false };
std::atomic<bool> m_circuitBreakerOpen{ false };
// Qt networking and timer
QNetworkAccessManager* m_networkAccessManager{ nullptr };
QTimer* m_processTimer{ nullptr };
QTimer* m_healthTimer{ nullptr };
// Configuration
size_t m_maxQueueSize{ 10000 };
bool m_backpressureEnabled{ true };
size_t m_memoryThresholdMB{ 50 };
std::string m_userHash;
// Error handling
ErrorCallback m_errorCallback;
std::atomic<int> m_consecutiveFailures{ 0 };
std::chrono::steady_clock::time_point m_lastReconnectAttempt;
// Pending network reply tracking (for synchronous crash flush)
std::atomic<int> m_pendingReplies{ 0 };
// Health monitoring
mutable HealthMetrics m_healthMetrics;
bool m_healthMonitoringEnabled{ false };
};