23
23
#include " brpc/controller.h"
24
24
#include " butil/strings/string_piece.h"
25
25
#include " echo.pb.h"
26
+ #include " bvar/multi_dimension.h"
26
27
27
28
int main (int argc, char * argv[]) {
28
29
testing::InitGoogleTest (&argc, argv);
@@ -45,7 +46,13 @@ enum STATE {
45
46
HELP = 0 ,
46
47
TYPE,
47
48
GAUGE,
48
- SUMMARY
49
+ SUMMARY,
50
+ COUNTER,
51
+ // When meets a line with a gauge/counter with labels, we have no
52
+ // idea the next line is a new HELP or the same gauge/counter just
53
+ // with different labels
54
+ HELP_OR_GAUGE,
55
+ HELP_OR_COUNTER,
49
56
};
50
57
51
58
TEST (PrometheusMetrics, sanity) {
@@ -54,10 +61,22 @@ TEST(PrometheusMetrics, sanity) {
54
61
ASSERT_EQ (0 , server.AddService (&echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE));
55
62
ASSERT_EQ (0 , server.Start (" 127.0.0.1:8614" , NULL ));
56
63
57
- brpc::Server server2;
58
- DummyEchoServiceImpl echo_svc2;
59
- ASSERT_EQ (0 , server2.AddService (&echo_svc2, brpc::SERVER_DOESNT_OWN_SERVICE));
60
- ASSERT_EQ (0 , server2.Start (" 127.0.0.1:8615" , NULL ));
64
+ const std::list<std::string> labels = {" label1" , " label2" };
65
+ bvar::MultiDimension<bvar::Adder<uint32_t > > my_madder (" madder" , labels);
66
+ bvar::Adder<uint32_t >* my_adder1 = my_madder.get_stats ({" val1" , " val2" });
67
+ ASSERT_TRUE (my_adder1);
68
+ *my_adder1 << 1 << 2 ;
69
+ bvar::Adder<uint32_t >* my_adder2 = my_madder.get_stats ({" val2" , " val3" });
70
+ ASSERT_TRUE (my_adder1);
71
+ *my_adder2 << 3 << 4 ;
72
+
73
+ bvar::MultiDimension<bvar::LatencyRecorder > my_mlat (" mlat" , labels);
74
+ bvar::LatencyRecorder* my_lat1 = my_mlat.get_stats ({" val1" , " val2" });
75
+ ASSERT_TRUE (my_lat1);
76
+ *my_lat1 << 1 << 2 ;
77
+ bvar::LatencyRecorder* my_lat2 = my_mlat.get_stats ({" val2" , " val3" });
78
+ ASSERT_TRUE (my_lat2);
79
+ *my_lat2 << 3 << 4 ;
61
80
62
81
brpc::Channel channel;
63
82
brpc::ChannelOptions channel_opts;
@@ -68,19 +87,22 @@ TEST(PrometheusMetrics, sanity) {
68
87
channel.CallMethod (NULL , &cntl, NULL , NULL , NULL );
69
88
ASSERT_FALSE (cntl.Failed ());
70
89
std::string res = cntl.response_attachment ().to_string ();
71
-
90
+ LOG (INFO) << " output: \n " << res;
72
91
size_t start_pos = 0 ;
73
92
size_t end_pos = 0 ;
93
+ size_t label_start = 0 ;
74
94
STATE state = HELP;
75
95
char name_help[128 ];
76
96
char name_type[128 ];
77
97
char type[16 ];
78
98
int matched = 0 ;
79
- int gauge_num = 0 ;
99
+ int num = 0 ;
80
100
bool summary_sum_gathered = false ;
81
101
bool summary_count_gathered = false ;
82
102
bool has_ever_summary = false ;
83
103
bool has_ever_gauge = false ;
104
+ bool has_ever_counter = false ; // brought in by mvar latency recorder
105
+ std::unordered_set<std::string> metric_name_set;
84
106
85
107
while ((end_pos = res.find (' \n ' , start_pos)) != butil::StringPiece::npos) {
86
108
res[end_pos] = ' \0 ' ; // safe;
@@ -98,21 +120,52 @@ TEST(PrometheusMetrics, sanity) {
98
120
state = GAUGE;
99
121
} else if (strcmp (type, " summary" ) == 0 ) {
100
122
state = SUMMARY;
123
+ } else if (strcmp (type, " counter" ) == 0 ) {
124
+ state = COUNTER;
101
125
} else {
102
- ASSERT_TRUE (false );
126
+ ASSERT_TRUE (false ) << " invalid type: " << type ;
103
127
}
128
+ ASSERT_EQ (0 , metric_name_set.count (name_type)) << " second TYPE line for metric name "
129
+ << name_type;
130
+ metric_name_set.insert (name_help);
104
131
break ;
132
+ case HELP_OR_GAUGE:
133
+ case HELP_OR_COUNTER:
134
+ matched = sscanf (res.data () + start_pos, " # HELP %s" , name_help);
135
+ // Try to figure out current line is a new COMMENT or not
136
+ if (matched == 1 ) {
137
+ state = HELP;
138
+ } else {
139
+ state = state == HELP_OR_GAUGE ? GAUGE : COUNTER;
140
+ }
141
+ res[end_pos] = ' \n ' ; // revert to original
142
+ continue ; // do not jump to next line
105
143
case GAUGE:
106
- matched = sscanf (res.data () + start_pos, " %s %d" , name_type, &gauge_num);
144
+ case COUNTER:
145
+ matched = sscanf (res.data () + start_pos, " %s %d" , name_type, &num);
107
146
ASSERT_EQ (2 , matched);
108
- ASSERT_STREQ (name_type, name_help);
109
- state = HELP;
110
- has_ever_gauge = true ;
147
+ if (state == GAUGE) {
148
+ has_ever_gauge = true ;
149
+ }
150
+ if (state == COUNTER) {
151
+ has_ever_counter = true ;
152
+ }
153
+ label_start = butil::StringPiece (name_type).find (" {" );
154
+ if (label_start == strlen (name_help)) { // mvar
155
+ ASSERT_EQ (name_type[strlen (name_type) - 1 ], ' }' );
156
+ ASSERT_TRUE (strncmp (name_type, name_help, strlen (name_help)) == 0 );
157
+ state = state == GAUGE ? HELP_OR_GAUGE : HELP_OR_COUNTER;
158
+ } else if (label_start == butil::StringPiece::npos) { // var
159
+ ASSERT_STREQ (name_type, name_help);
160
+ state = HELP;
161
+ } else { // invalid
162
+ ASSERT_TRUE (false );
163
+ }
111
164
break ;
112
165
case SUMMARY:
113
166
if (butil::StringPiece (res.data () + start_pos, end_pos - start_pos).find (" quantile=" )
114
167
== butil::StringPiece::npos) {
115
- matched = sscanf (res.data () + start_pos, " %s %d" , name_type, &gauge_num );
168
+ matched = sscanf (res.data () + start_pos, " %s %d" , name_type, &num );
116
169
ASSERT_EQ (2 , matched);
117
170
ASSERT_TRUE (strncmp (name_type, name_help, strlen (name_help)) == 0 );
118
171
if (butil::StringPiece (name_type).ends_with (" _sum" )) {
@@ -138,7 +191,7 @@ TEST(PrometheusMetrics, sanity) {
138
191
}
139
192
start_pos = end_pos + 1 ;
140
193
}
141
- ASSERT_TRUE (has_ever_gauge && has_ever_summary);
194
+ ASSERT_TRUE (has_ever_gauge && has_ever_summary && has_ever_counter );
142
195
ASSERT_EQ (0 , server.Stop (0 ));
143
196
ASSERT_EQ (0 , server.Join ());
144
197
}
0 commit comments