-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Add tags for stats extracted by configurable regexes. #1751
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0892986
488bcea
f95b506
3a365dc
6491456
7259085
c58a15c
86f0c31
d1a9e13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| #include <list> | ||
| #include <memory> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "envoy/common/pure.h" | ||
|
|
||
|
|
@@ -19,40 +20,91 @@ class Instance; | |
|
|
||
| namespace Stats { | ||
|
|
||
| /** | ||
| * General representation of a tag. | ||
| */ | ||
| struct Tag { | ||
| std::string name_; | ||
| std::string value_; | ||
| }; | ||
|
|
||
| class TagExtractor { | ||
| public: | ||
| virtual ~TagExtractor() {} | ||
|
|
||
| /** | ||
| * Identifier for this tag. | ||
| */ | ||
| virtual std::string name() const PURE; | ||
|
|
||
| /** | ||
| * Updates the tag extracted name and the set of tags by extracting the tag represented by this | ||
| * TagExtractor. If the tag is not represented in the current tag_extracted_name, nothing will be | ||
| * modified. | ||
| * @param name name from which the tag will be removed if found to exist. | ||
| * @param tags list of tags updated with the tag name and value if found in the | ||
| * name. | ||
| * @returns modified tag_extracted_name with the tag removed. | ||
| */ | ||
| virtual std::string updateTags(const std::string& name, std::vector<Tag>& tags) const PURE; | ||
| }; | ||
|
|
||
| typedef std::unique_ptr<TagExtractor> TagExtractorPtr; | ||
|
|
||
| /** | ||
| * General interface for all stats objects. | ||
| */ | ||
| class Metric { | ||
| public: | ||
| virtual ~Metric() {} | ||
| /** | ||
| * Returns the full name of the Metric. | ||
| */ | ||
| virtual std::string name() const PURE; | ||
|
|
||
| /** | ||
| * Returns a vector of configurable tags to identify this Metric. | ||
| */ | ||
| virtual const std::vector<Tag>& tags() const PURE; | ||
|
|
||
| /** | ||
| * Returns the name of the Metric with the portions designated as tags removed. | ||
| */ | ||
| virtual const std::string& tagExtractedName() const PURE; | ||
| }; | ||
|
|
||
| /** | ||
| * An always incrementing counter with latching capability. Each increment is added both to a | ||
| * global counter as well as periodic counter. Calling latch() returns the periodic counter and | ||
| * clears it. | ||
| */ | ||
| class Counter { | ||
| class Counter : public Metric { | ||
| public: | ||
| virtual ~Counter() {} | ||
| virtual void add(uint64_t amount) PURE; | ||
| virtual void inc() PURE; | ||
| virtual uint64_t latch() PURE; | ||
| virtual std::string name() PURE; | ||
| virtual void reset() PURE; | ||
| virtual bool used() PURE; | ||
| virtual uint64_t value() PURE; | ||
| virtual bool used() const PURE; | ||
| virtual uint64_t value() const PURE; | ||
| }; | ||
|
|
||
| typedef std::shared_ptr<Counter> CounterSharedPtr; | ||
|
|
||
| /** | ||
| * A gauge that can both increment and decrement. | ||
| */ | ||
| class Gauge { | ||
| class Gauge : public Metric { | ||
| public: | ||
| virtual ~Gauge() {} | ||
|
|
||
| virtual void add(uint64_t amount) PURE; | ||
| virtual void dec() PURE; | ||
| virtual void inc() PURE; | ||
| virtual std::string name() PURE; | ||
| virtual void set(uint64_t value) PURE; | ||
| virtual void sub(uint64_t amount) PURE; | ||
| virtual bool used() PURE; | ||
| virtual uint64_t value() PURE; | ||
| virtual bool used() const PURE; | ||
| virtual uint64_t value() const PURE; | ||
| }; | ||
|
|
||
| typedef std::shared_ptr<Gauge> GaugeSharedPtr; | ||
|
|
@@ -83,16 +135,28 @@ typedef std::unique_ptr<Timespan> TimespanPtr; | |
| /** | ||
| * A timer that can capture timespans. | ||
| */ | ||
| class Timer { | ||
| class Timer : public Metric { | ||
| public: | ||
| virtual ~Timer() {} | ||
|
|
||
| virtual TimespanPtr allocateSpan() PURE; | ||
| virtual std::string name() PURE; | ||
| virtual void recordDuration(std::chrono::milliseconds ms) PURE; | ||
| }; | ||
|
|
||
| typedef std::shared_ptr<Timer> TimerSharedPtr; | ||
|
|
||
| /** | ||
| * A histogram that captures values one at a time. | ||
| */ | ||
| class Histogram : public Metric { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Is it worth creating a full on histogram interface vs. just having Timer take some kind of flag as an indication to the stats sink? They are basically the same thing. |
||
| public: | ||
| virtual ~Histogram() {} | ||
|
|
||
| virtual void recordValue(uint64_t value) PURE; | ||
| }; | ||
|
|
||
| typedef std::shared_ptr<Histogram> HistogramSharedPtr; | ||
|
|
||
| /** | ||
| * A sink for stats. Each sink is responsible for writing stats to a backing store. | ||
| */ | ||
|
|
@@ -109,12 +173,12 @@ class Sink { | |
| /** | ||
| * Flush a counter delta. | ||
| */ | ||
| virtual void flushCounter(const std::string& name, uint64_t delta) PURE; | ||
| virtual void flushCounter(const Metric& counter, uint64_t delta) PURE; | ||
|
|
||
| /** | ||
| * Flush a gauge value. | ||
| */ | ||
| virtual void flushGauge(const std::string& name, uint64_t value) PURE; | ||
| virtual void flushGauge(const Metric& gauge, uint64_t value) PURE; | ||
|
|
||
| /** | ||
| * This will be called after beginFlush(), some number of flushCounter(), and some number of | ||
|
|
@@ -125,12 +189,12 @@ class Sink { | |
| /** | ||
| * Flush a histogram value. | ||
| */ | ||
| virtual void onHistogramComplete(const std::string& name, uint64_t value) PURE; | ||
| virtual void onHistogramComplete(const Metric& histogram, uint64_t value) PURE; | ||
|
|
||
| /** | ||
| * Flush a timespan value. | ||
| */ | ||
| virtual void onTimespanComplete(const std::string& name, std::chrono::milliseconds ms) PURE; | ||
| virtual void onTimespanComplete(const Metric& timespan, std::chrono::milliseconds ms) PURE; | ||
| }; | ||
|
|
||
| typedef std::unique_ptr<Sink> SinkPtr; | ||
|
|
@@ -157,12 +221,12 @@ class Scope { | |
| /** | ||
| * Deliver an individual histogram value to all registered sinks. | ||
| */ | ||
| virtual void deliverHistogramToSinks(const std::string& name, uint64_t value) PURE; | ||
| virtual void deliverHistogramToSinks(const Metric& histogram, uint64_t value) PURE; | ||
|
|
||
| /** | ||
| * Deliver an individual timespan completion to all registered sinks. | ||
| */ | ||
| virtual void deliverTimingToSinks(const std::string& name, std::chrono::milliseconds ms) PURE; | ||
| virtual void deliverTimingToSinks(const Metric& timer, std::chrono::milliseconds ms) PURE; | ||
|
|
||
| /** | ||
| * @return a counter within the scope's namespace. | ||
|
|
@@ -178,6 +242,11 @@ class Scope { | |
| * @return a timer within the scope's namespace. | ||
| */ | ||
| virtual Timer& timer(const std::string& name) PURE; | ||
|
|
||
| /** | ||
| * @return a histogram within the scope's namespace. | ||
| */ | ||
| virtual Histogram& histogram(const std::string& name) PURE; | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -196,6 +265,8 @@ class Store : public Scope { | |
| virtual std::list<GaugeSharedPtr> gauges() const PURE; | ||
| }; | ||
|
|
||
| typedef std::unique_ptr<Store> StorePtr; | ||
|
|
||
| /** | ||
| * The root of the stat store. | ||
| */ | ||
|
|
@@ -206,6 +277,11 @@ class StoreRoot : public Store { | |
| */ | ||
| virtual void addSink(Sink& sink) PURE; | ||
|
|
||
| /** | ||
| * Add an extractor to extract a portion of stats names as a tag. | ||
| */ | ||
| virtual void setTagExtractors(const std::vector<TagExtractorPtr>& tag_extractor) PURE; | ||
|
|
||
| /** | ||
| * Initialize the store for threading. This will be called once after all worker threads have | ||
| * been initialized. At this point the store can initialize itself for multi-threaded operation. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| #include "common/config/well_known_names.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Config { | ||
|
|
||
| std::unordered_map<std::string, std::string> TagNameValues::getRegexMapping() { | ||
| std::unordered_map<std::string, std::string> regex_mapping; | ||
|
|
||
| // cluster.<cluster_name>. | ||
| regex_mapping[CLUSTER_NAME] = "^cluster\\.(([^.]*)\\.)"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the non-greedy operator here might be fine as well, I wasn't aware of it until you pointed it out. If you have sufficient unit tests for the tag extraction, it should be pretty clear how it's behaving. It's probably clearer to write as a non-greedy regex if it works in this scenario. |
||
|
|
||
| // listener.<port>. | ||
| regex_mapping[LISTENER_PORT] = "^listener\\.((\\d+?)\\.)"; | ||
|
|
||
| // http.<stat_prefix>. | ||
| regex_mapping[HTTP_CONN_MANAGER_PREFIX] = "^http\\.(([^.]*)\\.)"; | ||
|
|
||
| // http.<stat_prefix>.user_agent.<user_agent>.[base_stat] = | ||
| regex_mapping[HTTP_USER_AGENT] = "^http(?=\\.).*?\\.user_agent\\.(([^.]*)\\.)\\w+?$"; | ||
|
|
||
| // listener.<port>.ssl.cipher.<cipher> | ||
| regex_mapping[SSL_CIPHER] = "^listener(?=\\.).*?\\.ssl\\.cipher(\\.([^.]*))$"; | ||
|
|
||
| // auth.clientssl.<stat_prefix>. | ||
| regex_mapping[CLIENTSSL_PREFIX] = "^auth\\.clientssl\\.(([^.]*)\\.)"; | ||
|
|
||
| // mongo.<stat_prefix>. | ||
| regex_mapping[MONGO_PREFIX] = "^mongo\\.(([^.]*)\\.)"; | ||
|
|
||
| // mongo.<stat_prefix>.cmd.<cmd>.[base_stat] = | ||
| regex_mapping[MONGO_CMD] = "^mongo(?=\\.).*?\\.cmd\\.(([^.]*)\\.)\\w+?$"; | ||
|
|
||
| // mongo.<stat_prefix>.collection.<collection>.query.[base_stat] = | ||
| regex_mapping[MONGO_COLLECTION] = "^mongo(?=\\.).*?\\.collection\\.(([^.]*)\\.).*?query.\\w+?$"; | ||
|
|
||
| // mongo.<stat_prefix>.collection.<collection>.callsite.<callsite>.query.[base_stat] = | ||
| regex_mapping[MONGO_CALLSITE] = "^mongo(?=\\.).*?\\.callsite\\.(([^.]*)\\.).*?query.\\w+?$"; | ||
|
|
||
| // ratelimit.<stat_prefix>. | ||
| regex_mapping[RATELIMIT_PREFIX] = "^ratelimit\\.(([^.]*)\\.)"; | ||
|
|
||
| // tcp.<stat_prefix>. | ||
| regex_mapping[TCP_PREFIX] = "^tcp\\.(([^.]*)\\.)"; | ||
|
|
||
| // http.<stat_prefix>.fault.<downstream-cluster>. | ||
| regex_mapping[FAULT_DOWNSTREAM_CLUSTER] = "^http(?=\\.).*?\\.fault\\.(([^.]*)\\.)"; | ||
|
|
||
| // http.<stat_prefix>.dynamodb.(operation or table.<table_name>.capacity).<operation_name>. | ||
| regex_mapping[DYNAMO_OPERATION] = | ||
| "^http(?=\\.).*?\\.dynamodb.(?:operation|table(?=\\.).*?\\.capacity)(\\.([^.]*))(?:\\." | ||
| "|$)"; | ||
|
|
||
| // http.<stat_prefix>.dynamodb.(table or error).<table_name>. | ||
| regex_mapping[DYNAMO_TABLE] = "^http(?=\\.).*?\\.dynamodb.(?:table|error)\\.(([^.]*)\\.)"; | ||
|
|
||
| // http.<stat_prefix>.dynamodb.table.<table_name>.capacity.<operation_name>.__partition_id=<last_seven_characters_from_partition_id> | ||
| regex_mapping[DYNAMO_PARTITION_ID] = | ||
| "^http(?=\\.).*?\\.dynamodb\\..+?(\\.__partition_id=(\\w{7}))$"; | ||
|
|
||
| // cluster.<route target cluster>.grpc.<grpc service>. | ||
| regex_mapping[GRPC_BRIDGE_SERVICE] = "^cluster(?=\\.).*?\\.grpc\\.(([^.]*)\\.)"; | ||
|
|
||
| // cluster.<route target cluster>.grpc.<grpc service>.<grpc method>.[base_stat] = | ||
| regex_mapping[GRPC_BRIDGE_METHOD] = "^cluster(?=\\.).*?\\.grpc(?=\\.).*\\.(([^.]*)\\.)\\w+?$"; | ||
|
|
||
| // vhost.<virtual host name>. | ||
| regex_mapping[VIRTUAL_HOST] = "^vhost\\.(([^.]*)\\.)"; | ||
|
|
||
| // vhost.<virtual host name>.vcluster.<virtual cluster name>.[base_stat] = | ||
| regex_mapping[VIRTUAL_CLUSTER] = "^vhost(?=\\.).*?\\.vcluster\\.(([^.]*)\\.)\\w+?$"; | ||
|
|
||
| // *_rq_<response_code> | ||
| regex_mapping[RESPONSE_CODE] = "_rq(_(\\d{3}))$"; | ||
|
|
||
| // *_rq_<response_code_class>xx | ||
| regex_mapping[RESPONSE_CODE_CLASS] = "_rq(_(\\dxx))$"; | ||
|
|
||
| return regex_mapping; | ||
| } | ||
|
|
||
| } // namespace Config | ||
| } // namespace Envoy | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The literal
tag_extracted_namenow no longer is a thing in this comment, so all references to it should be updated. Also, it's not really an "update" operation anymore.