Skip to content

Commit

Permalink
lib/tagset: add tag set as bitmask
Browse files Browse the repository at this point in the history
Add tag set as a bitmask, as part of refactoring lib.TagSet.

Update #755

silent linter

fix @imiric's review comments
  • Loading branch information
cuonglm committed Sep 30, 2019
1 parent 1d6fb7f commit 0ebf8c7
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 0 deletions.
94 changes: 94 additions & 0 deletions lib/tagset/tagset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package tagset

import (
"bytes"
"encoding/json"
"strings"
)

// TagSet is a bitmask that is used to keep track
// which system tags should be included with which metrics.
//go:generate enumer -type=TagSet -transform=snake -output tagset_gen.go
type TagSet uint32

//nolint: golint
const (
// Default system tags includes all of the system tags emitted with metrics by default.
Proto TagSet = 1 << iota
SubProto
Status
Method
URL
Name
Group
Check
Error
ErrorCode
TLSVersion

// System tags not enabled by default.
Iter
VU
OCSPStatus
IP
)

// Add adds a tag to tag set.
func (ts *TagSet) Add(tag TagSet) {
*ts |= tag
}

// Has checks a tag included in tag set.
func (ts *TagSet) Has(tag TagSet) bool {
return *ts&tag != 0
}

// FromList converts list of tags to TagSet
func FromList(tags []string) *TagSet {
ts := TagSet(0)
for _, tag := range tags {
if v, err := TagSetString(tag); err == nil {
ts.Add(v)
}
}
return &ts
}

// MarshalJSON converts the TagSet to a list (JS array).
func (ts *TagSet) MarshalJSON() ([]byte, error) {
var tags []string
for _, tag := range TagSetValues() {
if ts.Has(tag) {
tags = append(tags, tag.String())
}
}
return json.Marshal(tags)
}

// UnmarshalJSON converts the tag list back to expected tag set.
func (ts *TagSet) UnmarshalJSON(data []byte) error {
var tags []string
if err := json.Unmarshal(data, &tags); err != nil {
return err
}
if len(tags) != 0 {
*ts = *FromList(tags)
}
return nil
}

// UnmarshalText converts the tag list to TagSet.
func (ts *TagSet) UnmarshalText(data []byte) error {
var list = bytes.Split(data, []byte(","))

for _, key := range list {
key := strings.TrimSpace(string(key))
if key == "" {
continue
}
if v, err := TagSetString(key); err == nil {
ts.Add(v)
}
}
return nil
}
75 changes: 75 additions & 0 deletions lib/tagset/tagset_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions lib/tagset/tagset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package tagset

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestTagSetMarshalJSON(t *testing.T) {
var tests = []struct {
tagset TagSet
expected string
}{
{IP, `["ip"]`},
{0, `null`},
}

for _, tc := range tests {
ts := &tc.tagset
got, err := json.Marshal(ts)
require.Nil(t, err)
require.Equal(t, tc.expected, string(got))
}

}

func TestTagSet_UnmarshalJSON(t *testing.T) {
var tests = []struct {
tags []byte
sets []TagSet
}{
{[]byte(`[]`), []TagSet{}},
{[]byte(`["ip", "proto"]`), []TagSet{IP, Proto}},
}

for _, tc := range tests {
ts := new(TagSet)
require.Nil(t, json.Unmarshal(tc.tags, ts))
for _, tag := range tc.sets {
assert.True(t, ts.Has(tag))
}
}

}

func TestTagSetTextUnmarshal(t *testing.T) {
var testMatrix = map[string]TagSet{
"": 0,
"ip": IP,
"ip,proto": IP | Proto,
" ip , proto ": IP | Proto,
" ip , , proto ": IP | Proto,
" ip ,, proto ,,": IP | Proto,
}

for input, expected := range testMatrix {
var set = new(TagSet)
err := set.UnmarshalText([]byte(input))
require.NoError(t, err)
require.Equal(t, expected, *set)
}
}

0 comments on commit 0ebf8c7

Please sign in to comment.