1
#pragma once
2

            
3
#include "envoy/common/optref.h"
4
#include "envoy/extensions/access_loggers/dynamic_modules/v3/dynamic_modules.pb.h"
5
#include "envoy/stats/scope.h"
6
#include "envoy/stats/stats.h"
7

            
8
#include "source/common/common/statusor.h"
9
#include "source/common/stats/utility.h"
10
#include "source/extensions/dynamic_modules/abi/abi.h"
11
#include "source/extensions/dynamic_modules/dynamic_modules.h"
12

            
13
namespace Envoy {
14
namespace Extensions {
15
namespace AccessLoggers {
16
namespace DynamicModules {
17

            
18
// Type aliases for function pointers resolved from the module.
19
using OnAccessLoggerConfigNewType = decltype(&envoy_dynamic_module_on_access_logger_config_new);
20
using OnAccessLoggerConfigDestroyType =
21
    decltype(&envoy_dynamic_module_on_access_logger_config_destroy);
22
using OnAccessLoggerNewType = decltype(&envoy_dynamic_module_on_access_logger_new);
23
using OnAccessLoggerLogType = decltype(&envoy_dynamic_module_on_access_logger_log);
24
using OnAccessLoggerDestroyType = decltype(&envoy_dynamic_module_on_access_logger_destroy);
25
using OnAccessLoggerFlushType = decltype(&envoy_dynamic_module_on_access_logger_flush);
26

            
27
// The default custom stat namespace which prepends all user-defined metrics.
28
// This can be overridden via the ``metrics_namespace`` field in ``DynamicModuleConfig``.
29
constexpr absl::string_view DefaultMetricsNamespace = "dynamicmodulescustom";
30

            
31
/**
32
 * Configuration for dynamic module access loggers. This resolves and holds the symbols used for
33
 * access logging. Multiple access log instances may share this config.
34
 *
35
 * Note: Symbol resolution and in-module config creation are done in the factory function
36
 * newDynamicModuleAccessLogConfig() to provide graceful error handling. The constructor
37
 * only initializes basic members.
38
 */
39
class DynamicModuleAccessLogConfig {
40
public:
41
  /**
42
   * Constructor for the config. Symbol resolution is done in newDynamicModuleAccessLogConfig().
43
   * @param logger_name the name of the logger.
44
   * @param logger_config the configuration bytes for the logger.
45
   * @param metrics_namespace the namespace prefix for metrics emitted by this module.
46
   * @param dynamic_module the dynamic module to use.
47
   * @param stats_scope the stats scope for metrics.
48
   */
49
  DynamicModuleAccessLogConfig(const absl::string_view logger_name,
50
                               const absl::string_view logger_config,
51
                               const absl::string_view metrics_namespace,
52
                               Extensions::DynamicModules::DynamicModulePtr dynamic_module,
53
                               Stats::Scope& stats_scope);
54

            
55
  ~DynamicModuleAccessLogConfig();
56

            
57
  // The corresponding in-module configuration.
58
  envoy_dynamic_module_type_access_logger_config_module_ptr in_module_config_{nullptr};
59

            
60
  // The function pointers for the module related to the access logger. All required ones are
61
  // resolved during newDynamicModuleAccessLogConfig() and guaranteed non-nullptr after that.
62
  OnAccessLoggerConfigDestroyType on_config_destroy_{nullptr};
63
  OnAccessLoggerNewType on_logger_new_{nullptr};
64
  OnAccessLoggerLogType on_logger_log_{nullptr};
65
  OnAccessLoggerDestroyType on_logger_destroy_{nullptr};
66
  // Optional flush callback. Called before logger destruction during shutdown.
67
  OnAccessLoggerFlushType on_logger_flush_{nullptr};
68

            
69
  // ----------------------------- Metrics Support -----------------------------
70
  // Handle classes for storing defined metrics.
71

            
72
  class ModuleCounterHandle {
73
  public:
74
3
    ModuleCounterHandle(Stats::Counter& counter) : counter_(counter) {}
75
5
    void add(uint64_t value) const { counter_.add(value); }
76

            
77
  private:
78
    Stats::Counter& counter_;
79
  };
80

            
81
  class ModuleGaugeHandle {
82
  public:
83
1
    ModuleGaugeHandle(Stats::Gauge& gauge) : gauge_(gauge) {}
84
1
    void add(uint64_t value) const { gauge_.add(value); }
85
1
    void sub(uint64_t value) const { gauge_.sub(value); }
86
1
    void set(uint64_t value) const { gauge_.set(value); }
87

            
88
  private:
89
    Stats::Gauge& gauge_;
90
  };
91

            
92
  class ModuleHistogramHandle {
93
  public:
94
1
    ModuleHistogramHandle(Stats::Histogram& histogram) : histogram_(histogram) {}
95
1
    void recordValue(uint64_t value) const { histogram_.recordValue(value); }
96

            
97
  private:
98
    Stats::Histogram& histogram_;
99
  };
100

            
101
// We use 1-based IDs for the metrics in the ABI, so we need to convert them to 0-based indices
102
// for our internal storage. These helper functions do that conversion.
103
9
#define ID_TO_INDEX(id) ((id) - 1)
104

            
105
  // Methods for adding metrics during configuration.
106
3
  size_t addCounter(ModuleCounterHandle&& counter) {
107
3
    counters_.push_back(std::move(counter));
108
3
    return counters_.size();
109
3
  }
110

            
111
1
  size_t addGauge(ModuleGaugeHandle&& gauge) {
112
1
    gauges_.push_back(std::move(gauge));
113
1
    return gauges_.size();
114
1
  }
115

            
116
1
  size_t addHistogram(ModuleHistogramHandle&& histogram) {
117
1
    histograms_.push_back(std::move(histogram));
118
1
    return histograms_.size();
119
1
  }
120

            
121
  // Methods for getting metrics by ID.
122
6
  OptRef<const ModuleCounterHandle> getCounterById(size_t id) const {
123
6
    if (id == 0 || id > counters_.size()) {
124
1
      return {};
125
1
    }
126
5
    return counters_[ID_TO_INDEX(id)];
127
6
  }
128

            
129
4
  OptRef<const ModuleGaugeHandle> getGaugeById(size_t id) const {
130
4
    if (id == 0 || id > gauges_.size()) {
131
1
      return {};
132
1
    }
133
3
    return gauges_[ID_TO_INDEX(id)];
134
4
  }
135

            
136
2
  OptRef<const ModuleHistogramHandle> getHistogramById(size_t id) const {
137
2
    if (id == 0 || id > histograms_.size()) {
138
1
      return {};
139
1
    }
140
1
    return histograms_[ID_TO_INDEX(id)];
141
2
  }
142

            
143
  // Stats scope for metric creation.
144
  const Stats::ScopeSharedPtr stats_scope_;
145
  Stats::StatNamePool stat_name_pool_;
146

            
147
private:
148
  // Allow the factory function to access private members for initialization.
149
  friend absl::StatusOr<std::shared_ptr<DynamicModuleAccessLogConfig>>
150
  newDynamicModuleAccessLogConfig(const absl::string_view logger_name,
151
                                  const absl::string_view logger_config,
152
                                  const absl::string_view metrics_namespace,
153
                                  Extensions::DynamicModules::DynamicModulePtr dynamic_module,
154
                                  Stats::Scope& stats_scope);
155

            
156
  // The name of the logger passed in the constructor.
157
  const std::string logger_name_;
158

            
159
  // The configuration bytes for the logger.
160
  const std::string logger_config_;
161

            
162
  // The handle for the module.
163
  Extensions::DynamicModules::DynamicModulePtr dynamic_module_;
164

            
165
  // Metric storage.
166
  std::vector<ModuleCounterHandle> counters_;
167
  std::vector<ModuleGaugeHandle> gauges_;
168
  std::vector<ModuleHistogramHandle> histograms_;
169
};
170

            
171
using DynamicModuleAccessLogConfigSharedPtr = std::shared_ptr<DynamicModuleAccessLogConfig>;
172

            
173
/**
174
 * Creates a new DynamicModuleAccessLogConfig for the given configuration.
175
 * @param logger_name the name of the logger.
176
 * @param logger_config the configuration bytes for the logger.
177
 * @param metrics_namespace the namespace prefix for metrics emitted by this module.
178
 * @param dynamic_module the dynamic module to use.
179
 * @param stats_scope the stats scope for metrics.
180
 * @return a shared pointer to the new config object or an error if symbol resolution failed.
181
 */
182
absl::StatusOr<DynamicModuleAccessLogConfigSharedPtr> newDynamicModuleAccessLogConfig(
183
    const absl::string_view logger_name, const absl::string_view logger_config,
184
    const absl::string_view metrics_namespace,
185
    Extensions::DynamicModules::DynamicModulePtr dynamic_module, Stats::Scope& stats_scope);
186

            
187
} // namespace DynamicModules
188
} // namespace AccessLoggers
189
} // namespace Extensions
190
} // namespace Envoy