-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
127 lines (114 loc) · 3.65 KB
/
main.go
File metadata and controls
127 lines (114 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
"golang.org/x/sys/unix"
)
func getMemAvailable(s *bufio.Scanner) (int, error) {
for s.Scan() {
line := s.Text()
if strings.HasPrefix(line, "MemAvailable:") {
return strconv.Atoi(strings.TrimSpace(strings.TrimSuffix(line[len("MemAvailable:"):], "kB")))
}
}
if err := s.Err(); err != nil {
return 0, err
}
return 0, errors.New("failed to parse /proc/meminfo")
}
func getDiskAvailable(path string) (uint64, error) {
var statfs unix.Statfs_t
err := unix.Statfs(path, &statfs)
if err != nil {
return 0, err
}
return statfs.Bavail * uint64(statfs.Frsize) / 1024, err // return kilobytes, for consistence with MemAvailable
}
func getMetadata(metadataClient *imds.Client, path string) (string, error) {
var err error
if res, err := metadataClient.GetMetadata(context.Background(), &imds.GetMetadataInput{Path: path}); err == nil {
if resBytes, err := io.ReadAll(res.Content); err == nil {
return string(resBytes), err
}
}
return "", err
}
func main() {
procMeminfo, err := os.Open("/proc/meminfo")
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to open /proc/meminfo,", err)
os.Exit(1)
}
meminfoScanner := bufio.NewScanner(procMeminfo)
monitorDisk := os.Getenv("MONITOR_DISK") // Value is a path to monitor
metadataClient := imds.New(imds.Options{})
credentialsProvider := ec2rolecreds.New() // Only use EC2 instance credentials
region, err := getMetadata(metadataClient, "placement/availability-zone")
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to get the region from EC2 metadata,", err)
os.Exit(1)
}
region = region[:len(region)-1] // Drop AZ to get the region
instanceId, err := getMetadata(metadataClient, "instance-id")
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to get the instance id from EC2 metadata,", err)
os.Exit(1)
}
fmt.Println("Got metadata, region:", region, "instance-id:", instanceId)
cloudwatchClient := cloudwatch.New(cloudwatch.Options{
Credentials: aws.NewCredentialsCache(credentialsProvider),
Region: region,
})
ticker := time.Tick(time.Minute)
for timestamp := time.Now(); ; timestamp = <-ticker {
procMeminfo.Seek(0, 0)
memAvailable, err := getMemAvailable(meminfoScanner)
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to get MemAvailable:", err)
os.Exit(1)
}
metrics := []types.MetricDatum{
{
MetricName: aws.String("MemAvailable"),
Dimensions: []types.Dimension{{Name: aws.String("InstanceId"), Value: &instanceId}},
Timestamp: ×tamp,
Value: aws.Float64(float64(memAvailable / 1024)),
Unit: types.StandardUnitMegabytes,
},
}
if monitorDisk != "" {
diskAvailable, err := getDiskAvailable(monitorDisk)
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to get DiskAvailable:", err)
os.Exit(1)
}
metrics = append(metrics, types.MetricDatum{
MetricName: aws.String("DiskAvailable"),
Dimensions: []types.Dimension{{Name: aws.String("InstanceId"), Value: &instanceId}},
Timestamp: ×tamp,
Value: aws.Float64(float64(diskAvailable / 1024)),
Unit: types.StandardUnitMegabytes,
})
}
_, err = cloudwatchClient.PutMetricData(context.Background(), &cloudwatch.PutMetricDataInput{
Namespace: aws.String("Custom/EC2"),
MetricData: metrics,
})
if err != nil {
fmt.Fprintln(os.Stderr, "Sending the metric failed, ", err)
os.Exit(1)
}
}
}