Skip to content

Commit ed43fb1

Browse files
authored
Merge pull request #1 from jpra1113/master
Add snap-average-counter-processor
2 parents 65b14d6 + b0462a3 commit ed43fb1

12 files changed

Lines changed: 509 additions & 1 deletion

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
vendor
2+
/bin/snap-average-counter-processor

AUTHORS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Credits
2+
3+
## Development Lead
4+
5+
- Hyperpilotio [Hyperpilotio](https://github.com/Hyperpilotio)
6+
7+
## Contributors
8+
9+
None yet. Why not be the first?

CONTRIBUTING.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Contributing
2+
3+
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
4+
5+
You can contribute in many ways:
6+
7+
## Types of Contributions
8+
9+
### Report Bugs
10+
11+
Report bugs at https://github.com/Hyperpilotio/snap-average-counter-processor/issues.
12+
13+
If you are reporting a bug, please include:
14+
15+
* Your operating system name and version.
16+
* Any details about your local setup that might be helpful in troubleshooting.
17+
* Detailed steps to reproduce the bug.
18+
19+
### Fix Bugs
20+
21+
Look through the GitHub issues for bugs. Anything tagged with "bug"
22+
is open to whoever wants to implement it.
23+
24+
### Implement Features
25+
26+
Look through the GitHub issues for features. Anything tagged with "feature"
27+
is open to whoever wants to implement it.
28+
29+
### Write Documentation
30+
31+
snap-plugin could always use more documentation, whether as part of the
32+
official snap-plugin docs, in docstrings, or even on the web in blog posts,
33+
articles, and such.
34+
35+
### Submit Feedback
36+
37+
The best way to send feedback is to file an issue at https://github.com/Hyperpilotio/snap-average-counter-processor/issues.
38+
39+
If you are proposing a feature:
40+
41+
* Explain in detail how it would work.
42+
* Keep the scope as narrow as possible, to make it easier to implement.
43+
* Remember that this is a volunteer-driven project, and that contributions
44+
are welcome :)
45+
46+
## Get Started!
47+
48+
Ready to contribute? Here's how to set up `snap-plugin` for local development.
49+
50+
1. Fork the `snap-plugin` repo on GitHub.
51+
2. Clone your fork locally::
52+
53+
$ git clone git@github.com:your_name_here/snap-plugin.git
54+
55+
3. Create a branch for local development::
56+
57+
$ git checkout -b name-of-your-bugfix-or-feature
58+
59+
Now you can make your changes locally.
60+
61+
4. When you're done making changes, check that your changes pass the tests::
62+
63+
$ make test
64+
65+
6. Commit your changes and push your branch to GitHub::
66+
67+
$ git add .
68+
$ git commit -m "Your detailed description of your changes."
69+
$ git push origin name-of-your-bugfix-or-feature
70+
71+
7. Submit a pull request through the GitHub website.
72+
73+
Pull Request Guidelines
74+
-----------------------
75+
76+
Before you submit a pull request, check that it meets these guidelines:
77+
78+
1. The pull request should include tests.
79+
2. If the pull request adds functionality, the docs should be updated. Put
80+
your new functionality into a function with a docstring, and add the
81+
feature to the list in README.md.

Makefile

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
.PHONY: build build-alpine clean test help default
2+
3+
BIN_NAME=snap-average-counter-processor
4+
5+
VERSION := $(shell grep "const Version " version.go | sed -E 's/.*"(.+)"$$/\1/')
6+
GIT_COMMIT=$(shell git rev-parse HEAD)
7+
GIT_DIRTY=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true)
8+
IMAGE_NAME := "hyperpilot/snap-plugin"
9+
10+
default: test
11+
12+
help:
13+
@echo 'Management commands for snap-plugin:'
14+
@echo
15+
@echo 'Usage:'
16+
@echo ' make build Compile the project.'
17+
@echo ' make get-deps runs glide install, mostly used for ci.'
18+
19+
@echo ' make clean Clean the directory tree.'
20+
@echo
21+
22+
build:
23+
@echo "building ${BIN_NAME} ${VERSION}"
24+
@echo "GOPATH=${GOPATH}"
25+
CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags "-X main.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X main.VersionPrerelease=DEV" -o bin/${BIN_NAME}
26+
27+
build-linux:
28+
@echo "building ${BIN_NAME} ${VERSION}"
29+
@echo "GOPATH=${GOPATH}"
30+
GOOS=linux GOARCH=amd64 go build -ldflags "-X main.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X main.VersionPrerelease=DEV" -o bin/${BIN_NAME}
31+
32+
get-deps:
33+
glide install
34+
35+
clean:
36+
@test ! -e bin/${BIN_NAME} || rm bin/${BIN_NAME}
37+
38+
test:
39+
go test $(glide nv)
40+
41+
check: test

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1-
# snap-average-counter-processor
1+
# snap-average-counter-processor
2+
3+
Plugin for snap
4+
5+
## Getting started
6+
7+
This project requires Go to be installed. On OS X with Homebrew you can just run `brew install go`.
8+
9+
Running it then should be as simple as:
10+
11+
```console
12+
$ make
13+
```
14+
15+
### Testing
16+
17+
``make test``

agent/agent.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package agent
2+
3+
import (
4+
"errors"
5+
"os"
6+
"path"
7+
"strings"
8+
"time"
9+
10+
"github.com/intelsdi-x/snap-plugin-lib-go/v1/plugin"
11+
logging "github.com/op/go-logging"
12+
)
13+
14+
var log = logging.MustGetLogger("processor")
15+
var logFormatter = logging.MustStringFormatter(
16+
` %{level:.1s}%{time:0102 15:04:05.999999} %{pid} %{shortfile}] %{message}`,
17+
)
18+
19+
type FileLog struct {
20+
Name string
21+
Logger *logging.Logger
22+
LogFile *os.File
23+
}
24+
25+
type PreviousData struct {
26+
Data float64
27+
Create time.Time
28+
}
29+
30+
// Processor test processor
31+
type SnapProcessor struct {
32+
Cache map[string]PreviousData
33+
}
34+
35+
// NewProcessor generate processor
36+
func NewProcessor() plugin.Processor {
37+
return &SnapProcessor{
38+
Cache: make(map[string]PreviousData),
39+
}
40+
}
41+
42+
func NewLogger(filesPath string, name string) (*FileLog, error) {
43+
logDirPath := path.Join(filesPath, "log")
44+
if _, err := os.Stat(logDirPath); os.IsNotExist(err) {
45+
os.Mkdir(logDirPath, 0777)
46+
}
47+
48+
logFilePath := path.Join(logDirPath, name+".log")
49+
logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_RDWR, 0666)
50+
if err != nil {
51+
return nil, errors.New("Unable to create log file:" + err.Error())
52+
}
53+
54+
fileLog := logging.NewLogBackend(logFile, "["+name+"]", 0)
55+
fileLogLevel := logging.AddModuleLevel(fileLog)
56+
fileLogLevel.SetLevel(logging.INFO, "")
57+
fileLogBackend := logging.NewBackendFormatter(fileLog, logFormatter)
58+
59+
log.SetBackend(logging.SetBackend(fileLogBackend))
60+
61+
return &FileLog{
62+
Name: name,
63+
Logger: log,
64+
LogFile: logFile,
65+
}, nil
66+
}
67+
68+
// Process test process function
69+
func (p *SnapProcessor) Process(mts []plugin.Metric, cfg plugin.Config) ([]plugin.Metric, error) {
70+
processLog, err := NewLogger("/tmp", "processor")
71+
if err != nil {
72+
return mts, errors.New("Error creating process logger: " + err.Error())
73+
}
74+
defer processLog.LogFile.Close()
75+
76+
log := processLog.Logger
77+
log.Infof("Process received metric size: %d", len(mts))
78+
79+
namespacesConfig, err := cfg.GetString("namespaces")
80+
if err != nil {
81+
return mts, errors.New("Unable to read namespaces config: " + err.Error())
82+
}
83+
processNamespaces := strings.Split(namespacesConfig, ",")
84+
processNamespaces = append(processNamespaces, "")
85+
log.Infof("Process namespaces: %+v", processNamespaces)
86+
87+
filterMetricKeywordsConfig, err := cfg.GetString("filterMetricKeywords")
88+
if err != nil {
89+
return mts, errors.New("Unable to read filterMetricKeywords config: " + err.Error())
90+
}
91+
filterMetricKeywords := strings.Split(filterMetricKeywordsConfig, ",")
92+
log.Infof("Process filterMetricKeywords: %+v", filterMetricKeywords)
93+
94+
metrics := []plugin.Metric{}
95+
for _, mt := range mts {
96+
podNamespace, _ := mt.Tags["io.kubernetes.pod.namespace"]
97+
if inArray(podNamespace, processNamespaces) {
98+
averageData := p.caluAverageData(mt, filterMetricKeywords, log)
99+
if averageData != -1 {
100+
mt.Data = averageData
101+
mt.Tags["processed"] = "true"
102+
}
103+
metrics = append(metrics, mt)
104+
}
105+
}
106+
107+
log.Infof("Process filter metric size %d: ", len(metrics))
108+
log.Infof("Process filter metric %+v: ", metrics)
109+
return metrics, nil
110+
}
111+
112+
/*
113+
GetConfigPolicy() returns the configPolicy for your plugin.
114+
115+
A config policy is how users can provide configuration info to
116+
plugin. Here you define what sorts of config info your plugin
117+
needs and/or requires.
118+
*/
119+
func (p *SnapProcessor) GetConfigPolicy() (plugin.ConfigPolicy, error) {
120+
policy := plugin.NewConfigPolicy()
121+
return *policy, nil
122+
}
123+
124+
func (p *SnapProcessor) caluAverageData(
125+
mt plugin.Metric,
126+
filterMetricKeywords []string,
127+
log *logging.Logger) float64 {
128+
namespaces := mt.Namespace.Strings()
129+
mapKey := strings.Join(namespaces, "/")
130+
averageData := float64(-1)
131+
previousData, ok := p.Cache[mapKey]
132+
if ok {
133+
log.Infof("Find %s previous cache metric vaule: %+v", mapKey, previousData)
134+
diffSeconds := mt.Timestamp.Sub(previousData.Create).Seconds()
135+
diffValue := (convertInterface(mt.Data) - previousData.Data)
136+
if diffSeconds > 0 && diffValue > 0 {
137+
averageData = (convertInterface(mt.Data) - previousData.Data) / diffSeconds
138+
log.Infof("Calculate %s averageData(%f) on %s", mapKey, averageData, mt.Timestamp)
139+
}
140+
}
141+
142+
// filter do not need counter metric
143+
caluMetric := namespaces[len(namespaces)-1]
144+
filterCache := false
145+
for _, metricKeyword := range filterMetricKeywords {
146+
if strings.Contains(caluMetric, metricKeyword) {
147+
filterCache = true
148+
break
149+
}
150+
}
151+
152+
if !filterCache {
153+
p.Cache[mapKey] = PreviousData{
154+
Data: convertInterface(mt.Data),
155+
Create: mt.Timestamp,
156+
}
157+
log.Infof("Cache this time metric vaule: %+v", p.Cache[mapKey])
158+
}
159+
160+
return averageData
161+
}
162+
163+
func convertInterface(data interface{}) float64 {
164+
switch data.(type) {
165+
case int:
166+
return float64(data.(int))
167+
case int8:
168+
return float64(data.(int8))
169+
case int16:
170+
return float64(data.(int16))
171+
case int32:
172+
return float64(data.(int32))
173+
case int64:
174+
return float64(data.(int64))
175+
case uint64:
176+
return float64(data.(uint64))
177+
case float32:
178+
return float64(data.(float32))
179+
case float64:
180+
return float64(data.(float64))
181+
default:
182+
return float64(0)
183+
}
184+
}
185+
186+
func inArray(a string, list []string) bool {
187+
for _, b := range list {
188+
if b == a {
189+
return true
190+
}
191+
}
192+
return false
193+
}

agent/agent_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package agent
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/smartystreets/goconvey/convey"
7+
)
8+
9+
func TestProcessor(t *testing.T) {
10+
Convey("Test Processor", t, func() {
11+
Convey("Process int metric", func() {
12+
// metrics := []plugin.Metric{
13+
// plugin.Metric{
14+
// Namespace: plugin.NewNamespace("x", "y", "z"),
15+
// Config: map[string]interface{}{"pw": "123aB"},
16+
// Data: 345678,
17+
// Tags: map[string]string{"hello": "world"},
18+
// Unit: "int",
19+
// Timestamp: time.Now(),
20+
// },
21+
// }
22+
// mts, err := p.Process(metrics, plugin.Config{})
23+
// So(mts, ShouldNotBeNil)
24+
// So(err, ShouldBeNil)
25+
// So(mts[0].Data, ShouldEqual, 876543)
26+
})
27+
28+
Convey("Test GetConfigPolicy", func() {
29+
p := GodddQoSProcessor{}
30+
_, err := p.GetConfigPolicy()
31+
32+
Convey("No error returned", func() {
33+
So(err, ShouldBeNil)
34+
})
35+
36+
})
37+
})
38+
}

0 commit comments

Comments
 (0)