Skip to content

Commit

Permalink
Initial commit of host metrics virtual memory scraper for windows
Browse files Browse the repository at this point in the history
  • Loading branch information
james-bebbington committed May 19, 2020
1 parent 36023bd commit a936a5b
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 16 deletions.
14 changes: 8 additions & 6 deletions receiver/hostmetricsreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/loadscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/memoryscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/networkscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/virtualmemoryscraper"
)

// This file implements Factory for HostMetrics receiver.
Expand All @@ -52,12 +53,13 @@ type Factory struct {
func NewFactory() *Factory {
return &Factory{
scraperFactories: map[string]internal.Factory{
cpuscraper.TypeStr: &cpuscraper.Factory{},
diskscraper.TypeStr: &diskscraper.Factory{},
loadscraper.TypeStr: &loadscraper.Factory{},
filesystemscraper.TypeStr: &filesystemscraper.Factory{},
memoryscraper.TypeStr: &memoryscraper.Factory{},
networkscraper.TypeStr: &networkscraper.Factory{},
cpuscraper.TypeStr: &cpuscraper.Factory{},
diskscraper.TypeStr: &diskscraper.Factory{},
loadscraper.TypeStr: &loadscraper.Factory{},
filesystemscraper.TypeStr: &filesystemscraper.Factory{},
memoryscraper.TypeStr: &memoryscraper.Factory{},
networkscraper.TypeStr: &networkscraper.Factory{},
virtualmemoryscraper.TypeStr: &virtualmemoryscraper.Factory{},
},
}
}
Expand Down
30 changes: 20 additions & 10 deletions receiver/hostmetricsreceiver/hostmetrics_receiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ import (
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/cpuscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/diskscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/loadscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/memoryscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/networkscraper"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal/scraper/virtualmemoryscraper"
)

var standardMetrics = []string{
Expand All @@ -43,6 +45,9 @@ var standardMetrics = []string{
"host/disk/ops",
"host/disk/time",
"host/filesystem/used",
"host/load/1m",
"host/load/5m",
"host/load/15m",
"host/network/packets",
"host/network/dropped_packets",
"host/network/errors",
Expand All @@ -56,6 +61,7 @@ var systemSpecificMetrics = map[string][]string{
"freebsd": {"host/filesystem/inodes/used"},
"openbsd": {"host/filesystem/inodes/used"},
"solaris": {"host/filesystem/inodes/used"},
"windows": {"host/pagefile/percent_used", "host/memory/paging_rate"},
}

func TestGatherMetrics_EndToEnd(t *testing.T) {
Expand All @@ -64,20 +70,24 @@ func TestGatherMetrics_EndToEnd(t *testing.T) {
config := &Config{
CollectionInterval: 100 * time.Millisecond,
Scrapers: map[string]internal.Config{
cpuscraper.TypeStr: &cpuscraper.Config{ReportPerCPU: true},
diskscraper.TypeStr: &diskscraper.Config{},
filesystemscraper.TypeStr: &filesystemscraper.Config{},
memoryscraper.TypeStr: &memoryscraper.Config{},
networkscraper.TypeStr: &networkscraper.Config{},
cpuscraper.TypeStr: &cpuscraper.Config{ReportPerCPU: true},
diskscraper.TypeStr: &diskscraper.Config{},
filesystemscraper.TypeStr: &filesystemscraper.Config{},
loadscraper.TypeStr: &loadscraper.Config{},
memoryscraper.TypeStr: &memoryscraper.Config{},
networkscraper.TypeStr: &networkscraper.Config{},
virtualmemoryscraper.TypeStr: &virtualmemoryscraper.Config{},
},
}

factories := map[string]internal.Factory{
cpuscraper.TypeStr: &cpuscraper.Factory{},
diskscraper.TypeStr: &diskscraper.Factory{},
filesystemscraper.TypeStr: &filesystemscraper.Factory{},
memoryscraper.TypeStr: &memoryscraper.Factory{},
networkscraper.TypeStr: &networkscraper.Factory{},
cpuscraper.TypeStr: &cpuscraper.Factory{},
diskscraper.TypeStr: &diskscraper.Factory{},
filesystemscraper.TypeStr: &filesystemscraper.Factory{},
loadscraper.TypeStr: &loadscraper.Factory{},
memoryscraper.TypeStr: &memoryscraper.Factory{},
networkscraper.TypeStr: &networkscraper.Factory{},
virtualmemoryscraper.TypeStr: &virtualmemoryscraper.Factory{},
}

receiver, err := newHostMetricsReceiver(context.Background(), zap.NewNop(), config, factories, sink)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 virtualmemoryscraper

import "go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal"

// Config relating to VirtualMemory Metric Scraper.
type Config struct {
internal.ConfigSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 virtualmemoryscraper

import (
"context"
"errors"
"runtime"

"go.uber.org/zap"

"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal"
)

// This file implements Factory for VirtualMemory scraper.

const (
// The value of "type" key in configuration.
TypeStr = "virtualmemory"
)

// Factory is the Factory for scraper.
type Factory struct {
}

// CreateDefaultConfig creates the default configuration for the Scraper.
func (f *Factory) CreateDefaultConfig() internal.Config {
return &Config{}
}

// CreateMetricsScraper creates a scraper based on provided config.
func (f *Factory) CreateMetricsScraper(
ctx context.Context,
logger *zap.Logger,
config internal.Config,
) (internal.Scraper, error) {
if runtime.GOOS != "windows" {
return nil, errors.New("the virtual memory scraper is currently only supported on windows")
}

cfg := config.(*Config)
return newVirtualMemoryScraper(ctx, cfg), nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 virtualmemoryscraper

import (
"context"
"runtime"
"testing"

"github.com/stretchr/testify/assert"
"go.uber.org/zap"
)

func TestCreateDefaultConfig(t *testing.T) {
factory := &Factory{}
cfg := factory.CreateDefaultConfig()
assert.IsType(t, &Config{}, cfg)
}

func TestCreateMetricsScraper(t *testing.T) {
factory := &Factory{}
cfg := &Config{}

scraper, err := factory.CreateMetricsScraper(context.Background(), zap.NewNop(), cfg)

if runtime.GOOS == "windows" {
assert.NoError(t, err)
assert.NotNil(t, scraper)
} else {
assert.Error(t, err)
assert.Nil(t, scraper)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 virtualmemoryscraper

import (
"go.opentelemetry.io/collector/consumer/pdata"
)

// virtual memory metric constants

const (
typeLabelName = "type"
directionLabelName = "direction"
)

const (
majorTypeLabelValue = "major"
inDirectionLabelValue = "page_in"
outDirectionLabelValue = "page_out"
)

var metricPageFileUsedDescriptor = createMetricPageFileUsedDescriptor()

func createMetricPageFileUsedDescriptor() pdata.MetricDescriptor {
descriptor := pdata.NewMetricDescriptor()
descriptor.InitEmpty()
descriptor.SetName("host/pagefile/percent_used")
descriptor.SetDescription("Pagefile usage (Percent).")
descriptor.SetUnit("1")
descriptor.SetType(pdata.MetricTypeGaugeDouble)
return descriptor
}

var metricPagingPerSecondDescriptor = createMetricPagingPerSecondDescriptor()

func createMetricPagingPerSecondDescriptor() pdata.MetricDescriptor {
descriptor := pdata.NewMetricDescriptor()
descriptor.InitEmpty()
descriptor.SetName("host/memory/paging_rate")
descriptor.SetDescription("The number of paging operations per second.")
descriptor.SetUnit("1")
descriptor.SetType(pdata.MetricTypeGaugeDouble)
return descriptor
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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.

// +build !windows

package virtualmemoryscraper

import (
"context"

"go.opentelemetry.io/collector/consumer/pdata"
)

// scraper for VirtualMemory Metrics
type scraper struct {
config *Config
}

// newVirtualMemoryScraper creates a VirtualMemory Scraper
func newVirtualMemoryScraper(_ context.Context, cfg *Config) *scraper {
return &scraper{config: cfg}
}

// Initialize
func (s *scraper) Initialize(_ context.Context) error {
return nil
}

// Close
func (s *scraper) Close(_ context.Context) error {
return nil
}

// ScrapeMetrics
func (s *scraper) ScrapeMetrics(ctx context.Context) (pdata.MetricSlice, error) {
return pdata.NewMetricSlice(), nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2020, OpenTelemetry Authors
//
// 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 virtualmemoryscraper

import (
"context"
"runtime"
"testing"

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

"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/receiver/hostmetricsreceiver/internal"
)

type validationFn func(*testing.T, pdata.MetricSlice)

func TestScrapeMetrics(t *testing.T) {
createScraperAndValidateScrapedMetrics(t, &Config{}, func(t *testing.T, metrics pdata.MetricSlice) {
// expect 2 metrics
assert.Equal(t, 2, metrics.Len())

// expect a single datapoint for page file used metric
hostPageFileUsedMetric := metrics.At(0)
internal.AssertDescriptorEqual(t, metricPageFileUsedDescriptor, hostPageFileUsedMetric.MetricDescriptor())
assert.Equal(t, 1, hostPageFileUsedMetric.DoubleDataPoints().Len())

// expect an in & out datapoint for paging per second metric
pagingPerSecondMetric := metrics.At(1)
internal.AssertDescriptorEqual(t, metricPagingPerSecondDescriptor, pagingPerSecondMetric.MetricDescriptor())
assert.Equal(t, 2, pagingPerSecondMetric.DoubleDataPoints().Len())
internal.AssertDoubleMetricLabelHasValue(t, pagingPerSecondMetric, 0, typeLabelName, majorTypeLabelValue)
internal.AssertDoubleMetricLabelHasValue(t, pagingPerSecondMetric, 0, directionLabelName, inDirectionLabelValue)
internal.AssertDoubleMetricLabelHasValue(t, pagingPerSecondMetric, 1, typeLabelName, majorTypeLabelValue)
internal.AssertDoubleMetricLabelHasValue(t, pagingPerSecondMetric, 1, directionLabelName, outDirectionLabelValue)
})
}

func createScraperAndValidateScrapedMetrics(t *testing.T, config *Config, assertFn validationFn) {
if runtime.GOOS != "windows" {
t.Skip("Skipping virtual memory test on non-Windows OS")
}

scraper := newVirtualMemoryScraper(context.Background(), config)
err := scraper.Initialize(context.Background())
require.NoError(t, err, "Failed to initialize virtual memory scraper: %v", err)
defer func() { assert.NoError(t, scraper.Close(context.Background())) }()

metrics, err := scraper.ScrapeMetrics(context.Background())
require.NoError(t, err, "Failed to scrape metrics: %v", err)

assertFn(t, metrics)
}

0 comments on commit a936a5b

Please sign in to comment.