Files
engine/modules/agent_analytics/agent_analytics.h
ozan d291dcdc74 feat: 9 agentic engine modules for agent-native Godot
agent_api (HTTP server), agent_log (structured logging), agent_events (event bus),
agent_console (GameConsole), agent_replay (snapshots), agent_vision (depth/segmentation),
agent_fbx (bone remapping), agent_auth (multi-agent), agent_analytics (feature flags + tracking)

All modules compile clean with mono. Binary uploaded to S3 v1.0.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 03:44:28 +01:00

138 lines
4.4 KiB
C++

#pragma once
#include "core/object/class_db.h"
#include "core/object/object.h"
#include "core/os/mutex.h"
#include "core/string/ustring.h"
#include "core/variant/dictionary.h"
#include "core/variant/array.h"
// PostHog-like analytics + feature flags, built into the engine.
// Self-hosted: events stay local (JSONL) or are forwarded to a configured endpoint.
class AgentAnalytics : public Object {
GDCLASS(AgentAnalytics, Object);
static AgentAnalytics *singleton;
public:
static AgentAnalytics *get_singleton() { return singleton; }
struct AnalyticsEvent {
uint64_t id = 0;
uint64_t timestamp_msec = 0;
String event_name;
String distinct_id; // User/session/agent ID.
Dictionary properties;
};
struct FeatureFlag {
String key;
bool enabled = false;
Variant value; // Can be bool, string, int, etc.
Dictionary conditions; // Targeting rules.
float rollout_percentage = 100.0f;
String description;
};
struct Funnel {
String name;
Array steps; // Array of event names.
Dictionary step_counts; // step_name -> count.
};
private:
// Event storage.
static constexpr int EVENT_BUFFER_SIZE = 50000;
Vector<AnalyticsEvent> events;
uint64_t next_event_id = 1;
Mutex events_mutex;
// Feature flags.
HashMap<String, FeatureFlag> feature_flags;
Mutex flags_mutex;
// Session tracking.
String current_session_id;
String current_distinct_id;
uint64_t session_start = 0;
// Funnels.
HashMap<String, Funnel> funnels;
// File sink for event persistence.
bool file_sink_enabled = false;
String file_sink_path;
// Remote endpoint (optional — send events to external analytics).
String remote_endpoint;
String remote_api_key;
bool remote_enabled = false;
// A/B test groups.
HashMap<String, String> experiment_groups; // experiment_key -> group_name
void _write_event_to_file(const AnalyticsEvent &p_event);
void _send_event_to_remote(const AnalyticsEvent &p_event);
bool _evaluate_flag_conditions(const FeatureFlag &p_flag, const Dictionary &p_context);
String _generate_session_id();
protected:
static void _bind_methods();
public:
AgentAnalytics();
~AgentAnalytics();
// --- Event Tracking (PostHog capture equivalent) ---
void capture(const String &p_event, const Dictionary &p_properties = Dictionary());
void identify(const String &p_distinct_id, const Dictionary &p_properties = Dictionary());
void alias(const String &p_alias, const String &p_distinct_id);
// Session management.
void start_session(const String &p_distinct_id = "");
void end_session();
String get_session_id() const { return current_session_id; }
// Page/screen views (game equivalent: level/scene tracking).
void screen(const String &p_screen_name, const Dictionary &p_properties = Dictionary());
// --- Feature Flags ---
bool is_feature_enabled(const String &p_key, const Dictionary &p_context = Dictionary());
Variant get_feature_flag(const String &p_key, const Variant &p_default = Variant());
void set_feature_flag(const String &p_key, bool p_enabled, const Variant &p_value = Variant(), float p_rollout = 100.0f, const String &p_description = "");
void remove_feature_flag(const String &p_key);
Array get_all_flags() const;
bool load_flags_from_file(const String &p_path = "res://feature_flags.json");
bool save_flags_to_file(const String &p_path = "res://feature_flags.json");
// --- A/B Testing ---
String get_experiment_group(const String &p_experiment_key, const Array &p_groups);
Dictionary get_experiment_results(const String &p_experiment_key);
// --- Funnels ---
void define_funnel(const String &p_name, const Array &p_steps);
Dictionary get_funnel_stats(const String &p_name);
// --- Query ---
Array get_events(int p_count = 100, const String &p_event_name = "", uint64_t p_since_msec = 0);
int get_event_count(const String &p_event_name = "");
Dictionary get_event_counts_by_name(); // {event_name: count}
// --- Configuration ---
void enable_file_sink(const String &p_path = "user://analytics.jsonl");
void disable_file_sink();
void set_remote_endpoint(const String &p_endpoint, const String &p_api_key);
void disable_remote();
void set_distinct_id(const String &p_id) { current_distinct_id = p_id; }
String get_distinct_id() const { return current_distinct_id; }
// --- Super Properties (attached to every event) ---
Dictionary super_properties;
void set_super_property(const String &p_key, const Variant &p_value);
void remove_super_property(const String &p_key);
void clear_super_properties();
void clear();
};