remappers/hostmetrics/filesystem.go (125 lines of code) (raw):

// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you 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 hostmetrics import ( "github.com/elastic/opentelemetry-lib/remappers/internal/remappedmetric" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) // DeviceMetrics holds metrics data for a device type deviceMetrics struct { totalUsage int64 usedBytes int64 totalInodeUsage int64 } type deviceKey struct { device string mpoint string fstype string } type number interface { ~int64 | ~float64 } func remapFilesystemMetrics( src, out pmetric.MetricSlice, _ pcommon.Resource, mutator func(pmetric.NumberDataPoint), ) error { var timestamp pcommon.Timestamp deviceMetricsMap := make(map[deviceKey]*deviceMetrics) for i := 0; i < src.Len(); i++ { metric := src.At(i) switch metric.Name() { case "system.filesystem.usage", "system.filesystem.inodes.usage": dataPoints := metric.Sum().DataPoints() for j := 0; j < dataPoints.Len(); j++ { dp := dataPoints.At(j) value := dp.IntValue() timestamp = dp.Timestamp() key, ok := getDeviceKey(dp) if !ok { continue } if _, exists := deviceMetricsMap[key]; !exists { deviceMetricsMap[key] = &deviceMetrics{} } dmetrics := deviceMetricsMap[key] if state, ok := dp.Attributes().Get("state"); ok { switch state.Str() { case "used": if metric.Name() == "system.filesystem.usage" { dmetrics.totalUsage += value dmetrics.usedBytes += value addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.used.bytes", key.device, key.mpoint, key.fstype, value) } else { dmetrics.totalInodeUsage += value } case "free": if metric.Name() == "system.filesystem.usage" { dmetrics.totalUsage += value addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.free", key.device, key.mpoint, key.fstype, value) addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.available", key.device, key.mpoint, key.fstype, value) } else { dmetrics.totalInodeUsage += value addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.free_files", key.device, key.mpoint, key.fstype, value) } } } } } } for key, dmetrics := range deviceMetricsMap { device, mpoint, fstype := key.device, key.mpoint, key.fstype if dmetrics.totalUsage > 0 { addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.total", device, mpoint, fstype, dmetrics.totalUsage) usedPercentage := float64(dmetrics.usedBytes) / float64(dmetrics.totalUsage) addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.used.pct", device, mpoint, fstype, usedPercentage) } if dmetrics.totalInodeUsage > 0 { addFileSystemMetrics(out, timestamp, mutator, "system.filesystem.files", device, mpoint, fstype, dmetrics.totalInodeUsage) } } return nil } func addFileSystemMetrics[T number](out pmetric.MetricSlice, timestamp pcommon.Timestamp, mutator func(pmetric.NumberDataPoint), name, device, mpoint, fstype string, value T, ) { var intValue *int64 var doubleValue *float64 if i, ok := any(value).(int64); ok { intValue = &i } else if d, ok := any(value).(float64); ok { doubleValue = &d } remappedmetric.Add(out, remappedmetric.ChainedMutator( mutator, func(dp pmetric.NumberDataPoint) { dp.Attributes().PutStr("system.filesystem.device_name", device) dp.Attributes().PutStr("system.filesystem.mount_point", mpoint) dp.Attributes().PutStr("system.filesystem.type", fstype) }), remappedmetric.Metric{ DataType: pmetric.MetricTypeSum, Name: name, Timestamp: timestamp, IntValue: intValue, DoubleValue: doubleValue, }, ) } func getDeviceKey(dp pmetric.NumberDataPoint) (key deviceKey, ok bool) { device, ok := dp.Attributes().Get("device") if !ok { return } mpoint, ok := dp.Attributes().Get("mountpoint") if !ok { return } fstype, ok := dp.Attributes().Get("type") if !ok { return } key = deviceKey{device: device.Str(), mpoint: mpoint.Str(), fstype: fstype.Str()} return }