1
#pragma once
2

            
3
#include <functional>
4
#include <string>
5
#include <vector>
6

            
7
#include "envoy/common/time.h"
8

            
9
#include "source/common/common/logger.h"
10
#include "source/common/common/random_generator.h"
11
#include "source/extensions/tracers/xray/reservoir.h"
12
#include "source/extensions/tracers/xray/sampling_strategy.h"
13

            
14
#include "absl/strings/string_view.h"
15

            
16
namespace Envoy {
17
namespace Extensions {
18
namespace Tracers {
19
namespace XRay {
20

            
21
/**
22
 * This class encompasses the algorithm used when deciding whether to sample a given request.
23
 * The rule contains wildcard strings for matching a request based on its hostname, HTTP method or
24
 * URL path. A request must match on all 3 parts before this rule is applied.
25
 * If the rule applies, then |fixed_target| determines how many requests to sample per second.
26
 * While, rate determines the percentage of requests to sample after that within the same second.
27
 *
28
 * By default, this tracer records the first request each second, and five percent of
29
 * any additional requests.
30
 */
31
class LocalizedSamplingRule {
32
public:
33
  /**
34
   * Creates a default sampling rule that has the default |fixed_target| and default |rate| set.
35
   */
36
  static LocalizedSamplingRule createDefault();
37

            
38
  LocalizedSamplingRule(uint32_t fixed_target, double rate)
39
44
      : fixed_target_(fixed_target), rate_(rate), reservoir_(fixed_target_) {}
40

            
41
  /**
42
   * Determines whether Hostname, HTTP method and URL path match the given request.
43
   */
44
  bool appliesTo(const SamplingRequest& request) const;
45

            
46
  /**
47
   * Set the hostname to match against.
48
   * This value can contain wildcard characters such as '*' or '?'.
49
   */
50
6
  void setHost(absl::string_view host) { host_ = std::string(host); }
51

            
52
  /**
53
   * Set the HTTP method to match against.
54
   * This value can contain wildcard characters such as '*' or '?'.
55
   */
56
6
  void setHttpMethod(absl::string_view http_method) { http_method_ = std::string(http_method); }
57

            
58
  /**
59
   * Set the URL path to match against.
60
   * This value can contain wildcard characters such as '*' or '?'.
61
   */
62
6
  void setUrlPath(absl::string_view url_path) { url_path_ = std::string(url_path); }
63

            
64
  /**
65
   * Set the minimum number of requests to sample per second.
66
   */
67
25
  void setFixedTarget(uint32_t fixed_target) {
68
25
    fixed_target_ = fixed_target;
69
25
    reservoir_ = Reservoir(fixed_target);
70
25
  }
71

            
72
  /**
73
   * Set the percentage of requests to sample _after_ sampling |fixed_target| requests per second.
74
   */
75
25
  void setRate(double rate) { rate_ = rate; }
76
88
  double rate() const { return rate_; }
77
77
  Reservoir& reservoir() { return reservoir_; }
78

            
79
private:
80
  std::string host_;
81
  std::string http_method_;
82
  std::string url_path_;
83
  uint32_t fixed_target_;
84
  double rate_;
85
  Reservoir reservoir_;
86
};
87

            
88
/**
89
 * The manifest represents the set of sampling rules (custom and default) used to match incoming
90
 * requests.
91
 */
92
class LocalizedSamplingManifest {
93
public:
94
  /**
95
   * Create a default manifest. The default manifest is used when a custom manifest does not exist
96
   * or failed to parse. The default manifest, will have an empty set of custom rules.
97
   */
98
  static LocalizedSamplingManifest createDefault() {
99
    return LocalizedSamplingManifest{LocalizedSamplingRule::createDefault()};
100
  }
101

            
102
  /**
103
   * Create a manifest by de-serializing the input string as JSON representation of the sampling
104
   * rules.
105
   * @param sampling_rules_json JSON representation of X-Ray localized sampling rules.
106
   */
107
  explicit LocalizedSamplingManifest(const std::string& sampling_rules_json);
108

            
109
  /**
110
   * Create a manifest by assigning the argument rule as the default rule. The set of custom rules
111
   * in this manifest will be empty.
112
   * @param default_rule A localized sampling rule that will be assigned as the default rule.
113
   */
114
  explicit LocalizedSamplingManifest(const LocalizedSamplingRule& default_rule)
115
      : default_rule_(default_rule) {}
116

            
117
  /**
118
   * @return default sampling rule
119
   */
120
74
  LocalizedSamplingRule& defaultRule() { return default_rule_; }
121

            
122
  /**
123
   * @return the user-defined sampling rules
124
   */
125
51
  std::vector<LocalizedSamplingRule>& customRules() { return custom_rules_; }
126

            
127
  /**
128
   * @return true if this manifest has a set of custom rules; otherwise false.
129
   */
130
105
  bool hasCustomRules() const { return !custom_rules_.empty(); }
131

            
132
private:
133
  LocalizedSamplingRule default_rule_;
134
  std::vector<LocalizedSamplingRule> custom_rules_;
135
};
136

            
137
class LocalizedSamplingStrategy : public SamplingStrategy {
138
public:
139
  LocalizedSamplingStrategy(const std::string& sampling_rules_json, Random::RandomGenerator& rng,
140
                            TimeSource& time_source)
141
38
      : SamplingStrategy(rng), manifest_(sampling_rules_json), time_source_(time_source) {}
142

            
143
  /**
144
   * Determines if an incoming request matches one of the sampling rules in the local manifest.
145
   * If a match is found, then the request might be traced based on the sampling percentages etc.
146
   * determined by the matching rule.
147
   */
148
  bool shouldTrace(const SamplingRequest& sampling_request) override;
149

            
150
46
  const LocalizedSamplingManifest manifest() const { return manifest_; }
151

            
152
private:
153
  bool shouldTrace(LocalizedSamplingRule& rule);
154
  LocalizedSamplingManifest manifest_;
155
  TimeSource& time_source_;
156
};
157

            
158
} // namespace XRay
159
} // namespace Tracers
160
} // namespace Extensions
161
} // namespace Envoy