Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
5facb628
Commit
5facb628
authored
Jul 18, 2017
by
Shyam Jeedigunta
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add apiserver metric for response sizes split by namespace scope
parent
d368afd8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
92 additions
and
38 deletions
+92
-38
proxy.go
staging/src/k8s.io/apiserver/pkg/endpoints/handlers/proxy.go
+13
-5
installer.go
staging/src/k8s.io/apiserver/pkg/endpoints/installer.go
+30
-19
metrics.go
...ing/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go
+39
-12
maxinflight.go
...ng/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go
+5
-1
timeout.go
staging/src/k8s.io/apiserver/pkg/server/filters/timeout.go
+5
-1
No files found.
staging/src/k8s.io/apiserver/pkg/endpoints/handlers/proxy.go
View file @
5facb628
...
@@ -53,18 +53,22 @@ type ProxyHandler struct {
...
@@ -53,18 +53,22 @@ type ProxyHandler struct {
}
}
func
(
r
*
ProxyHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
r
*
ProxyHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
reqStart
:=
time
.
Now
()
proxyHandlerTraceID
:=
rand
.
Int63
()
proxyHandlerTraceID
:=
rand
.
Int63
()
var
verb
string
var
verb
,
apiResource
,
subresource
,
scope
string
var
apiResource
,
subresource
string
var
httpCode
int
var
httpCode
int
reqStart
:=
time
.
Now
()
defer
func
()
{
defer
func
()
{
responseLength
:=
0
if
rw
,
ok
:=
w
.
(
*
metrics
.
ResponseWriterDelegator
);
ok
{
responseLength
=
rw
.
ContentLength
()
}
metrics
.
Monitor
(
metrics
.
Monitor
(
verb
,
apiResource
,
subresource
,
verb
,
apiResource
,
subresource
,
scope
,
net
.
GetHTTPClient
(
req
),
net
.
GetHTTPClient
(
req
),
w
.
Header
()
.
Get
(
"Content-Type"
),
w
.
Header
()
.
Get
(
"Content-Type"
),
httpCode
,
reqStart
,
httpCode
,
re
sponseLength
,
re
qStart
,
)
)
}()
}()
...
@@ -88,6 +92,10 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -88,6 +92,10 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
}
verb
=
requestInfo
.
Verb
verb
=
requestInfo
.
Verb
namespace
,
resource
,
subresource
,
parts
:=
requestInfo
.
Namespace
,
requestInfo
.
Resource
,
requestInfo
.
Subresource
,
requestInfo
.
Parts
namespace
,
resource
,
subresource
,
parts
:=
requestInfo
.
Namespace
,
requestInfo
.
Resource
,
requestInfo
.
Subresource
,
requestInfo
.
Parts
scope
=
"cluster"
if
namespace
!=
""
{
scope
=
"namespace"
}
ctx
=
request
.
WithNamespace
(
ctx
,
namespace
)
ctx
=
request
.
WithNamespace
(
ctx
,
namespace
)
if
len
(
parts
)
<
2
{
if
len
(
parts
)
<
2
{
...
...
staging/src/k8s.io/apiserver/pkg/endpoints/installer.go
View file @
5facb628
This diff is collapsed.
Click to expand it.
staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go
View file @
5facb628
...
@@ -18,6 +18,7 @@ package metrics
...
@@ -18,6 +18,7 @@ package metrics
import
(
import
(
"bufio"
"bufio"
//"fmt"
"net"
"net"
"net/http"
"net/http"
"regexp"
"regexp"
...
@@ -26,6 +27,7 @@ import (
...
@@ -26,6 +27,7 @@ import (
"time"
"time"
utilnet
"k8s.io/apimachinery/pkg/util/net"
utilnet
"k8s.io/apimachinery/pkg/util/net"
//utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"github.com/emicklei/go-restful"
"github.com/emicklei/go-restful"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus"
...
@@ -44,7 +46,7 @@ var (
...
@@ -44,7 +46,7 @@ var (
requestLatencies
=
prometheus
.
NewHistogramVec
(
requestLatencies
=
prometheus
.
NewHistogramVec
(
prometheus
.
HistogramOpts
{
prometheus
.
HistogramOpts
{
Name
:
"apiserver_request_latencies"
,
Name
:
"apiserver_request_latencies"
,
Help
:
"Response latency distribution in microseconds for each verb, resource and
client
."
,
Help
:
"Response latency distribution in microseconds for each verb, resource and
subresource
."
,
// Use buckets ranging from 125 ms to 8 seconds.
// Use buckets ranging from 125 ms to 8 seconds.
Buckets
:
prometheus
.
ExponentialBuckets
(
125000
,
2.0
,
7
),
Buckets
:
prometheus
.
ExponentialBuckets
(
125000
,
2.0
,
7
),
},
},
...
@@ -53,12 +55,21 @@ var (
...
@@ -53,12 +55,21 @@ var (
requestLatenciesSummary
=
prometheus
.
NewSummaryVec
(
requestLatenciesSummary
=
prometheus
.
NewSummaryVec
(
prometheus
.
SummaryOpts
{
prometheus
.
SummaryOpts
{
Name
:
"apiserver_request_latencies_summary"
,
Name
:
"apiserver_request_latencies_summary"
,
Help
:
"Response latency summary in microseconds for each verb
and
resource."
,
Help
:
"Response latency summary in microseconds for each verb
, resource and sub
resource."
,
// Make the sliding window of 1h.
// Make the sliding window of 1h.
MaxAge
:
time
.
Hour
,
MaxAge
:
time
.
Hour
,
},
},
[]
string
{
"verb"
,
"resource"
,
"subresource"
},
[]
string
{
"verb"
,
"resource"
,
"subresource"
},
)
)
responseSizes
=
prometheus
.
NewHistogramVec
(
prometheus
.
HistogramOpts
{
Name
:
"apiserver_response_sizes"
,
Help
:
"Response size distribution in bytes for each verb, resource, subresource and scope (namespace/cluster)."
,
// Use buckets ranging from 1000 bytes (1KB) to 10^9 bytes (1GB).
Buckets
:
prometheus
.
ExponentialBuckets
(
1000
,
10.0
,
7
),
},
[]
string
{
"verb"
,
"resource"
,
"subresource"
,
"scope"
},
)
kubectlExeRegexp
=
regexp
.
MustCompile
(
`^.*((?i:kubectl\.exe))`
)
kubectlExeRegexp
=
regexp
.
MustCompile
(
`^.*((?i:kubectl\.exe))`
)
)
)
...
@@ -67,20 +78,25 @@ func Register() {
...
@@ -67,20 +78,25 @@ func Register() {
prometheus
.
MustRegister
(
requestCounter
)
prometheus
.
MustRegister
(
requestCounter
)
prometheus
.
MustRegister
(
requestLatencies
)
prometheus
.
MustRegister
(
requestLatencies
)
prometheus
.
MustRegister
(
requestLatenciesSummary
)
prometheus
.
MustRegister
(
requestLatenciesSummary
)
prometheus
.
MustRegister
(
responseSizes
)
}
}
// Monitor records a request to the apiserver endpoints that follow the Kubernetes API conventions. verb must be
// Monitor records a request to the apiserver endpoints that follow the Kubernetes API conventions. verb must be
// uppercase to be backwards compatible with existing monitoring tooling.
// uppercase to be backwards compatible with existing monitoring tooling.
func
Monitor
(
verb
,
resource
,
subresource
,
client
,
contentType
string
,
httpCod
e
int
,
reqStart
time
.
Time
)
{
func
Monitor
(
verb
,
resource
,
subresource
,
scope
,
client
,
contentType
string
,
httpCode
,
respSiz
e
int
,
reqStart
time
.
Time
)
{
elapsed
:=
float64
((
time
.
Since
(
reqStart
))
/
time
.
Microsecond
)
elapsed
:=
float64
((
time
.
Since
(
reqStart
))
/
time
.
Microsecond
)
requestCounter
.
WithLabelValues
(
verb
,
resource
,
subresource
,
client
,
contentType
,
codeToString
(
httpCode
))
.
Inc
()
requestCounter
.
WithLabelValues
(
verb
,
resource
,
subresource
,
client
,
contentType
,
codeToString
(
httpCode
))
.
Inc
()
requestLatencies
.
WithLabelValues
(
verb
,
resource
,
subresource
)
.
Observe
(
elapsed
)
requestLatencies
.
WithLabelValues
(
verb
,
resource
,
subresource
)
.
Observe
(
elapsed
)
requestLatenciesSummary
.
WithLabelValues
(
verb
,
resource
,
subresource
)
.
Observe
(
elapsed
)
requestLatenciesSummary
.
WithLabelValues
(
verb
,
resource
,
subresource
)
.
Observe
(
elapsed
)
// We are only interested in response sizes of read requests.
if
verb
==
"GET"
||
verb
==
"LIST"
{
responseSizes
.
WithLabelValues
(
verb
,
resource
,
subresource
,
scope
)
.
Observe
(
float64
(
respSize
))
}
}
}
// MonitorRequest handles standard transformations for client and the reported verb and then invokes Monitor to record
// MonitorRequest handles standard transformations for client and the reported verb and then invokes Monitor to record
// a request. verb must be uppercase to be backwards compatible with existing monitoring tooling.
// a request. verb must be uppercase to be backwards compatible with existing monitoring tooling.
func
MonitorRequest
(
request
*
http
.
Request
,
verb
,
resource
,
subresource
,
contentType
string
,
httpCod
e
int
,
reqStart
time
.
Time
)
{
func
MonitorRequest
(
request
*
http
.
Request
,
verb
,
resource
,
subresource
,
scope
,
contentType
string
,
httpCode
,
respSiz
e
int
,
reqStart
time
.
Time
)
{
reportedVerb
:=
verb
reportedVerb
:=
verb
if
verb
==
"LIST"
{
if
verb
==
"LIST"
{
// see apimachinery/pkg/runtime/conversion.go Convert_Slice_string_To_bool
// see apimachinery/pkg/runtime/conversion.go Convert_Slice_string_To_bool
...
@@ -90,23 +106,25 @@ func MonitorRequest(request *http.Request, verb, resource, subresource, contentT
...
@@ -90,23 +106,25 @@ func MonitorRequest(request *http.Request, verb, resource, subresource, contentT
}
}
}
}
}
}
client
:=
cleanUserAgent
(
utilnet
.
GetHTTPClient
(
request
))
client
:=
cleanUserAgent
(
utilnet
.
GetHTTPClient
(
request
))
Monitor
(
reportedVerb
,
resource
,
subresource
,
client
,
contentType
,
httpCod
e
,
reqStart
)
Monitor
(
reportedVerb
,
resource
,
subresource
,
scope
,
client
,
contentType
,
httpCode
,
respSiz
e
,
reqStart
)
}
}
func
Reset
()
{
func
Reset
()
{
requestCounter
.
Reset
()
requestCounter
.
Reset
()
requestLatencies
.
Reset
()
requestLatencies
.
Reset
()
requestLatenciesSummary
.
Reset
()
requestLatenciesSummary
.
Reset
()
responseSizes
.
Reset
()
}
}
// InstrumentRouteFunc works like Prometheus' InstrumentHandlerFunc but wraps
// InstrumentRouteFunc works like Prometheus' InstrumentHandlerFunc but wraps
// the go-restful RouteFunction instead of a HandlerFunc
// the go-restful RouteFunction instead of a HandlerFunc
func
InstrumentRouteFunc
(
verb
,
resource
,
subresource
string
,
routeFunc
restful
.
RouteFunction
)
restful
.
RouteFunction
{
func
InstrumentRouteFunc
(
verb
,
resource
,
subresource
,
scope
string
,
routeFunc
restful
.
RouteFunction
)
restful
.
RouteFunction
{
return
restful
.
RouteFunction
(
func
(
request
*
restful
.
Request
,
response
*
restful
.
Response
)
{
return
restful
.
RouteFunction
(
func
(
request
*
restful
.
Request
,
response
*
restful
.
Response
)
{
now
:=
time
.
Now
()
now
:=
time
.
Now
()
delegate
:=
&
r
esponseWriterDelegator
{
ResponseWriter
:
response
.
ResponseWriter
}
delegate
:=
&
R
esponseWriterDelegator
{
ResponseWriter
:
response
.
ResponseWriter
}
_
,
cn
:=
response
.
ResponseWriter
.
(
http
.
CloseNotifier
)
_
,
cn
:=
response
.
ResponseWriter
.
(
http
.
CloseNotifier
)
_
,
fl
:=
response
.
ResponseWriter
.
(
http
.
Flusher
)
_
,
fl
:=
response
.
ResponseWriter
.
(
http
.
Flusher
)
...
@@ -121,7 +139,7 @@ func InstrumentRouteFunc(verb, resource, subresource string, routeFunc restful.R
...
@@ -121,7 +139,7 @@ func InstrumentRouteFunc(verb, resource, subresource string, routeFunc restful.R
routeFunc
(
request
,
response
)
routeFunc
(
request
,
response
)
MonitorRequest
(
request
.
Request
,
verb
,
resource
,
subresource
,
rw
.
Header
()
.
Get
(
"Content-Type"
),
delegate
.
status
,
now
)
MonitorRequest
(
request
.
Request
,
verb
,
resource
,
subresource
,
scope
,
delegate
.
Header
()
.
Get
(
"Content-Type"
),
delegate
.
Status
(),
delegate
.
ContentLength
()
,
now
)
})
})
}
}
...
@@ -135,7 +153,8 @@ func cleanUserAgent(ua string) string {
...
@@ -135,7 +153,8 @@ func cleanUserAgent(ua string) string {
return
ua
return
ua
}
}
type
responseWriterDelegator
struct
{
// ResponseWriterDelegator interface wraps http.ResponseWriter to additionally record content-length, status-code, etc.
type
ResponseWriterDelegator
struct
{
http
.
ResponseWriter
http
.
ResponseWriter
status
int
status
int
...
@@ -143,13 +162,13 @@ type responseWriterDelegator struct {
...
@@ -143,13 +162,13 @@ type responseWriterDelegator struct {
wroteHeader
bool
wroteHeader
bool
}
}
func
(
r
*
r
esponseWriterDelegator
)
WriteHeader
(
code
int
)
{
func
(
r
*
R
esponseWriterDelegator
)
WriteHeader
(
code
int
)
{
r
.
status
=
code
r
.
status
=
code
r
.
wroteHeader
=
true
r
.
wroteHeader
=
true
r
.
ResponseWriter
.
WriteHeader
(
code
)
r
.
ResponseWriter
.
WriteHeader
(
code
)
}
}
func
(
r
*
r
esponseWriterDelegator
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
func
(
r
*
R
esponseWriterDelegator
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
if
!
r
.
wroteHeader
{
if
!
r
.
wroteHeader
{
r
.
WriteHeader
(
http
.
StatusOK
)
r
.
WriteHeader
(
http
.
StatusOK
)
}
}
...
@@ -158,8 +177,16 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
...
@@ -158,8 +177,16 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
return
n
,
err
return
n
,
err
}
}
func
(
r
*
ResponseWriterDelegator
)
Status
()
int
{
return
r
.
status
}
func
(
r
*
ResponseWriterDelegator
)
ContentLength
()
int
{
return
int
(
r
.
written
)
}
type
fancyResponseWriterDelegator
struct
{
type
fancyResponseWriterDelegator
struct
{
*
r
esponseWriterDelegator
*
R
esponseWriterDelegator
}
}
func
(
f
*
fancyResponseWriterDelegator
)
CloseNotify
()
<-
chan
bool
{
func
(
f
*
fancyResponseWriterDelegator
)
CloseNotify
()
<-
chan
bool
{
...
...
staging/src/k8s.io/apiserver/pkg/server/filters/maxinflight.go
View file @
5facb628
...
@@ -109,7 +109,11 @@ func WithMaxInFlightLimit(
...
@@ -109,7 +109,11 @@ func WithMaxInFlightLimit(
}
}
}
}
}
}
metrics
.
MonitorRequest
(
r
,
strings
.
ToUpper
(
requestInfo
.
Verb
),
requestInfo
.
Resource
,
requestInfo
.
Subresource
,
""
,
errors
.
StatusTooManyRequests
,
time
.
Now
())
scope
:=
"cluster"
if
requestInfo
.
Namespace
!=
""
{
scope
=
"namespace"
}
metrics
.
MonitorRequest
(
r
,
strings
.
ToUpper
(
requestInfo
.
Verb
),
requestInfo
.
Resource
,
requestInfo
.
Subresource
,
""
,
scope
,
errors
.
StatusTooManyRequests
,
0
,
time
.
Now
())
tooManyRequests
(
r
,
w
)
tooManyRequests
(
r
,
w
)
}
}
}
}
...
...
staging/src/k8s.io/apiserver/pkg/server/filters/timeout.go
View file @
5facb628
...
@@ -60,7 +60,11 @@ func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMa
...
@@ -60,7 +60,11 @@ func WithTimeoutForNonLongRunningRequests(handler http.Handler, requestContextMa
}
}
now
:=
time
.
Now
()
now
:=
time
.
Now
()
metricFn
:=
func
()
{
metricFn
:=
func
()
{
metrics
.
MonitorRequest
(
req
,
strings
.
ToUpper
(
requestInfo
.
Verb
),
requestInfo
.
Resource
,
requestInfo
.
Subresource
,
""
,
http
.
StatusInternalServerError
,
now
)
scope
:=
"cluster"
if
requestInfo
.
Namespace
!=
""
{
scope
=
"namespace"
}
metrics
.
MonitorRequest
(
req
,
strings
.
ToUpper
(
requestInfo
.
Verb
),
requestInfo
.
Resource
,
requestInfo
.
Subresource
,
""
,
scope
,
http
.
StatusInternalServerError
,
0
,
now
)
}
}
return
time
.
After
(
globalTimeout
),
metricFn
,
apierrors
.
NewServerTimeout
(
schema
.
GroupResource
{
Group
:
requestInfo
.
APIGroup
,
Resource
:
requestInfo
.
Resource
},
requestInfo
.
Verb
,
0
)
return
time
.
After
(
globalTimeout
),
metricFn
,
apierrors
.
NewServerTimeout
(
schema
.
GroupResource
{
Group
:
requestInfo
.
APIGroup
,
Resource
:
requestInfo
.
Resource
},
requestInfo
.
Verb
,
0
)
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment