101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
// Copyright (c) 2017 Uber Technologies, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package rpcmetrics
|
|
|
|
// NameNormalizer is used to convert the endpoint names to strings
|
|
// that can be safely used as tags in the metrics.
|
|
type NameNormalizer interface {
|
|
Normalize(name string) string
|
|
}
|
|
|
|
// DefaultNameNormalizer converts endpoint names so that they contain only characters
|
|
// from the safe charset [a-zA-Z0-9-./_]. All other characters are replaced with '-'.
|
|
var DefaultNameNormalizer = &SimpleNameNormalizer{
|
|
SafeSets: []SafeCharacterSet{
|
|
&Range{From: 'a', To: 'z'},
|
|
&Range{From: 'A', To: 'Z'},
|
|
&Range{From: '0', To: '9'},
|
|
&Char{'-'},
|
|
&Char{'_'},
|
|
&Char{'/'},
|
|
&Char{'.'},
|
|
},
|
|
Replacement: '-',
|
|
}
|
|
|
|
// SimpleNameNormalizer uses a set of safe character sets.
|
|
type SimpleNameNormalizer struct {
|
|
SafeSets []SafeCharacterSet
|
|
Replacement byte
|
|
}
|
|
|
|
// SafeCharacterSet determines if the given character is "safe"
|
|
type SafeCharacterSet interface {
|
|
IsSafe(c byte) bool
|
|
}
|
|
|
|
// Range implements SafeCharacterSet
|
|
type Range struct {
|
|
From, To byte
|
|
}
|
|
|
|
// IsSafe implements SafeCharacterSet
|
|
func (r *Range) IsSafe(c byte) bool {
|
|
return c >= r.From && c <= r.To
|
|
}
|
|
|
|
// Char implements SafeCharacterSet
|
|
type Char struct {
|
|
Val byte
|
|
}
|
|
|
|
// IsSafe implements SafeCharacterSet
|
|
func (ch *Char) IsSafe(c byte) bool {
|
|
return c == ch.Val
|
|
}
|
|
|
|
// Normalize checks each character in the string against SafeSets,
|
|
// and if it's not safe substitutes it with Replacement.
|
|
func (n *SimpleNameNormalizer) Normalize(name string) string {
|
|
var retMe []byte
|
|
nameBytes := []byte(name)
|
|
for i, b := range nameBytes {
|
|
if n.safeByte(b) {
|
|
if retMe != nil {
|
|
retMe[i] = b
|
|
}
|
|
} else {
|
|
if retMe == nil {
|
|
retMe = make([]byte, len(nameBytes))
|
|
copy(retMe[0:i], nameBytes[0:i])
|
|
}
|
|
retMe[i] = n.Replacement
|
|
}
|
|
}
|
|
if retMe == nil {
|
|
return name
|
|
}
|
|
return string(retMe)
|
|
}
|
|
|
|
// safeByte checks if b against all safe charsets.
|
|
func (n *SimpleNameNormalizer) safeByte(b byte) bool {
|
|
for i := range n.SafeSets {
|
|
if n.SafeSets[i].IsSafe(b) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|