@@ -20,16 +20,17 @@ import (
2020const metricKeySeparator = "|"
2121
2222var (
23- requestCounts = expvar .NewMap ("authtranslator_requests_total" )
24- rateLimitCounts = expvar .NewMap ("authtranslator_rate_limit_events_total" )
25- authFailureCounts = expvar .NewMap ("authtranslator_auth_failures_total" )
26- internalResponseCounts = expvar .NewMap ("authtranslator_internal_responses_total" )
27- upstreamStatusCounts = expvar .NewMap ("authtranslator_upstream_responses_total" )
28- requestDurations = expvar .NewMap ("authtranslator_request_duration_seconds" )
29- LastReloadTime = expvar .NewString ("authtranslator_last_reload" )
30- durationHistsMu sync.Mutex
31- durationHists = make (map [string ]* histogram )
32- durationBuckets = []float64 {0.1 , 0.25 , 0.5 , 1 , 2.5 , 5 , 10 }
23+ requestCounts = expvar .NewMap ("authtranslator_requests_total" )
24+ rateLimitCounts = expvar .NewMap ("authtranslator_rate_limit_events_total" )
25+ authFailureCounts = expvar .NewMap ("authtranslator_auth_failures_total" )
26+ internalResponseCounts = expvar .NewMap ("authtranslator_internal_responses_total" )
27+ upstreamStatusCounts = expvar .NewMap ("authtranslator_upstream_responses_total" )
28+ upstreamRoundtripDurations = newDurationMetric ("authtranslator_upstream_roundtrip_duration_seconds" )
29+ endToEndDurations = newDurationMetric ("authtranslator_end_to_end_duration_seconds" )
30+ preProxyDurations = newDurationMetric ("authtranslator_pre_proxy_duration_seconds" )
31+ responseProcessingDurations = newDurationMetric ("authtranslator_response_processing_duration_seconds" )
32+ LastReloadTime = expvar .NewString ("authtranslator_last_reload" )
33+ durationBuckets = []float64 {0.1 , 0.25 , 0.5 , 1 , 2.5 , 5 , 10 }
3334)
3435
3536type histogram struct {
@@ -39,13 +40,29 @@ type histogram struct {
3940 sum float64
4041}
4142
43+ type durationMetric struct {
44+ name string
45+ exp * expvar.Map
46+
47+ mu sync.Mutex
48+ hists map [string ]* histogram
49+ }
50+
4251func newHistogram () * histogram {
4352 return & histogram {
4453 buckets : durationBuckets ,
4554 counts : make ([]uint64 , len (durationBuckets )+ 1 ),
4655 }
4756}
4857
58+ func newDurationMetric (name string ) * durationMetric {
59+ return & durationMetric {
60+ name : name ,
61+ exp : expvar .NewMap (name ),
62+ hists : make (map [string ]* histogram ),
63+ }
64+ }
65+
4966func init () {
5067 LastReloadTime .Set (time .Now ().Format (time .RFC3339 ))
5168}
@@ -89,7 +106,7 @@ func (h *histogram) String() string {
89106 return string (buf )
90107}
91108
92- func (h * histogram ) writeProm (w http.ResponseWriter , integ string ) {
109+ func (h * histogram ) writeProm (w http.ResponseWriter , name , integ string ) {
93110 h .mu .Lock ()
94111 buckets := append ([]float64 (nil ), h .buckets ... )
95112 counts := append ([]uint64 (nil ), h .counts ... )
@@ -98,12 +115,51 @@ func (h *histogram) writeProm(w http.ResponseWriter, integ string) {
98115 var cum uint64
99116 for i , b := range buckets {
100117 cum += counts [i ]
101- fmt .Fprintf (w , "authtranslator_request_duration_seconds_bucket {integration=%q,le=%q} %d\n " , integ , strconv .FormatFloat (b , 'f' , - 1 , 64 ), cum )
118+ fmt .Fprintf (w , "%s_bucket {integration=%q,le=%q} %d\n " , name , integ , strconv .FormatFloat (b , 'f' , - 1 , 64 ), cum )
102119 }
103120 cum += counts [len (buckets )]
104- fmt .Fprintf (w , "authtranslator_request_duration_seconds_bucket{integration=%q,le=\" +Inf\" } %d\n " , integ , cum )
105- fmt .Fprintf (w , "authtranslator_request_duration_seconds_sum{integration=%q} %f\n " , integ , sum )
106- fmt .Fprintf (w , "authtranslator_request_duration_seconds_count{integration=%q} %d\n " , integ , cum )
121+ fmt .Fprintf (w , "%s_bucket{integration=%q,le=\" +Inf\" } %d\n " , name , integ , cum )
122+ fmt .Fprintf (w , "%s_sum{integration=%q} %f\n " , name , integ , sum )
123+ fmt .Fprintf (w , "%s_count{integration=%q} %d\n " , name , integ , cum )
124+ }
125+
126+ func (m * durationMetric ) Record (integration string , d time.Duration ) {
127+ m .mu .Lock ()
128+ h , ok := m .hists [integration ]
129+ if ! ok {
130+ h = newHistogram ()
131+ m .hists [integration ] = h
132+ m .exp .Set (integration , h )
133+ }
134+ m .mu .Unlock ()
135+ h .Observe (d .Seconds ())
136+ }
137+
138+ func (m * durationMetric ) Reset () {
139+ m .exp .Init ()
140+ m .mu .Lock ()
141+ m .hists = make (map [string ]* histogram )
142+ m .mu .Unlock ()
143+ }
144+
145+ func (m * durationMetric ) WriteProm (w http.ResponseWriter ) {
146+ writePromType (w , m .name , "histogram" )
147+
148+ type histSnapshot struct {
149+ name string
150+ h * histogram
151+ }
152+
153+ m .mu .Lock ()
154+ hists := make ([]histSnapshot , 0 , len (m .hists ))
155+ for name , h := range m .hists {
156+ hists = append (hists , histSnapshot {name : name , h : h })
157+ }
158+ m .mu .Unlock ()
159+
160+ for _ , hs := range hists {
161+ hs .h .writeProm (w , m .name , hs .name )
162+ }
107163}
108164
109165// IncRequest increments the request counter for the integration.
@@ -128,17 +184,29 @@ func RecordStatus(integration string, status int) {
128184 upstreamStatusCounts .Add (key , 1 )
129185}
130186
131- // RecordDuration records the upstream request duration.
132- func RecordDuration (integration string , d time.Duration ) {
133- durationHistsMu .Lock ()
134- h , ok := durationHists [integration ]
135- if ! ok {
136- h = newHistogram ()
137- durationHists [integration ] = h
138- requestDurations .Set (integration , h )
139- }
140- durationHistsMu .Unlock ()
141- h .Observe (d .Seconds ())
187+ // RecordUpstreamRoundtripDuration records the duration from proxy handoff until
188+ // AuthTranslator receives the upstream response.
189+ func RecordUpstreamRoundtripDuration (integration string , d time.Duration ) {
190+ upstreamRoundtripDurations .Record (integration , d )
191+ }
192+
193+ // RecordEndToEndDuration records full request latency as observed by the
194+ // AuthTranslator handler.
195+ func RecordEndToEndDuration (integration string , d time.Duration ) {
196+ endToEndDurations .Record (integration , d )
197+ }
198+
199+ // RecordPreProxyDuration records request-side processing time before
200+ // AuthTranslator proxies upstream or returns a local response.
201+ func RecordPreProxyDuration (integration string , d time.Duration ) {
202+ preProxyDurations .Record (integration , d )
203+ }
204+
205+ // RecordResponseProcessingDuration records response-side processing time inside
206+ // AuthTranslator after an upstream response is received and before streaming the
207+ // body to the client begins.
208+ func RecordResponseProcessingDuration (integration string , d time.Duration ) {
209+ responseProcessingDurations .Record (integration , d )
142210}
143211
144212func writePromType (w http.ResponseWriter , name , metricType string ) {
@@ -152,20 +220,10 @@ func WriteProm(w http.ResponseWriter) {
152220 requestCounts .Do (func (kv expvar.KeyValue ) {
153221 fmt .Fprintf (w , "authtranslator_requests_total{integration=%q} %s\n " , kv .Key , kv .Value .String ())
154222 })
155- writePromType (w , "authtranslator_request_duration_seconds" , "histogram" )
156- durationHistsMu .Lock ()
157- type histSnapshot struct {
158- name string
159- h * histogram
160- }
161- hists := make ([]histSnapshot , 0 , len (durationHists ))
162- for name , h := range durationHists {
163- hists = append (hists , histSnapshot {name : name , h : h })
164- }
165- durationHistsMu .Unlock ()
166- for _ , hs := range hists {
167- hs .h .writeProm (w , hs .name )
168- }
223+ upstreamRoundtripDurations .WriteProm (w )
224+ endToEndDurations .WriteProm (w )
225+ preProxyDurations .WriteProm (w )
226+ responseProcessingDurations .WriteProm (w )
169227 writePromType (w , "authtranslator_rate_limit_events_total" , "counter" )
170228 rateLimitCounts .Do (func (kv expvar.KeyValue ) {
171229 fmt .Fprintf (w , "authtranslator_rate_limit_events_total{integration=%q} %s\n " , kv .Key , kv .Value .String ())
0 commit comments