Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f411fa1
add `--insecure-skip-verify` CLI argument to skip certificate validat…
def Oct 15, 2024
dd275c6
Merge pull request #132 from coroot/insecure_skip_verify
def Oct 15, 2024
1d3c74b
fix .NET app name collisions
def Oct 15, 2024
ad6ad6a
Merge pull request #133 from coroot/fix_dotnet_apps_collisions
def Oct 15, 2024
150658e
collapsed metrics of CronJob pods
def Oct 17, 2024
f1d06c3
Merge pull request #134 from coroot/collapsing_metrics_of_cronjob_pods
def Oct 17, 2024
b809e4d
collapse high-cardinality metrics (TCP, L7) related to interactions …
def Nov 1, 2024
667b87c
Merge pull request #136 from coroot/collapse-s3-metrics
def Nov 1, 2024
5867b91
add support for Talos Linux runtime
def Nov 1, 2024
7ebae09
Merge pull request #137 from coroot/talos_support
def Nov 1, 2024
ec07a0b
image: switch to `ubi9` base
apetruhin Nov 5, 2024
5941c6a
application types: add `valkey` and `dragonfly`
def Nov 12, 2024
5eecdd7
Merge pull request #139 from coroot/redis_alternatives
def Nov 12, 2024
a72509b
skip connections to link-local IPs
def Nov 13, 2024
4785312
group HTTP statuses (e.g., 2xx, 4xx) to reduce the number of metrics …
def Nov 13, 2024
c7356a0
DNS metric optimization
def Nov 14, 2024
4ede0a3
Merge pull request #140 from coroot/metric_optimizations
def Nov 14, 2024
3ebb3d5
tls: support "invalid" go versions
apetruhin Nov 22, 2024
480ea30
Merge pull request #142 from coroot/tls_invalid_go_versions_support
apetruhin Nov 26, 2024
a8ee24d
conntrack: use `Dump` in `GetActualDestination`
apetruhin Nov 22, 2024
55183ef
Merge pull request #143 from coroot/conntrack_get_via_dump
apetruhin Nov 26, 2024
5430687
build: gzip+base64 ebpf progs
apetruhin Nov 26, 2024
a87bc34
ebpf: apply extra padding for tracepoints arguments (5.14-el9 kernels)
apetruhin Nov 26, 2024
92f532f
Merge pull request #144 from coroot/openshift_fixes
apetruhin Nov 26, 2024
8d332f3
Revert "conntrack: use `Dump` in `GetActualDestination`"
apetruhin Nov 27, 2024
3eea121
build: upgrade `go`, `cilium/ebpf`, `pyroscope/ebpf`
apetruhin Nov 27, 2024
ffd3971
ebpf: buffered read from perfmaps
apetruhin Nov 27, 2024
e02bf28
Merge pull request #145 from coroot/ebpf_perfmap_buffered_read
apetruhin Nov 27, 2024
1279365
eBPF-based resolving of actual TCP connection destinations (conntrack)
def Nov 29, 2024
1dac238
Merge pull request #146 from coroot/ebpf_conntrack
def Nov 29, 2024
6702469
persist OTel tracers in containers
def Nov 29, 2024
f51d5cc
Merge pull request #147 from coroot/persistent_tracer_per_container
def Nov 29, 2024
a1524ba
logs: multilineCollectorTimeout=1s (instead of 100ms)
def Nov 29, 2024
649b1bf
Merge pull request #148 from coroot/log_reader_optimization
def Nov 29, 2024
1e16696
file events: skip reading `fdinfo` for previously seen mounts
def Dec 4, 2024
98808a0
Merge pull request #149 from coroot/fdinfo_optimization
def Dec 4, 2024
bcf6e0b
optimize FQDNs normalization
def Dec 4, 2024
42a8e5c
Merge pull request #150 from coroot/fast_fqdn_normalization
def Dec 4, 2024
b996840
fix kernel version validation (#152)
apetruhin Dec 9, 2024
29f5d2c
Merge pull request #153 from coroot/kernel_version_fix
apetruhin Dec 9, 2024
3d08524
conntrack: use kprobe on `nf_confirm` for 5.3+ kernels where it is ex…
def Dec 10, 2024
803664f
fix cgroup detection
def Dec 10, 2024
d7bdc41
use kprobe on `path_get` to determine the relevant mount for file ope…
def Dec 10, 2024
9386698
Merge pull request #154 from coroot/ebpf_compatibility
def Dec 10, 2024
a989468
conntrack: use kprobe on `nf_ct_deliver_cached_events` for tracking c…
def Dec 11, 2024
6dcf8fe
Merge pull request #156 from coroot/nf_ct_deliver_cached_events
def Dec 11, 2024
638facd
cgroup: don't report CPU, Memory, and IO usage for `/` cgroup
def Dec 16, 2024
7f46467
Merge pull request #157 from coroot/fix_resource_usage_metrics
def Dec 16, 2024
1217e5e
add support for ClickHouse native protocol
def Dec 19, 2024
7adb723
Merge pull request #159 from coroot/clickhouse_protocol_support
def Dec 19, 2024
fedbdbd
add support for Zookeeper client protocol
def Dec 20, 2024
f6185e0
Merge pull request #160 from coroot/zk_protocol_support
def Dec 20, 2024
da1d263
handle missing `nf_conntrack` gracefully
def Dec 23, 2024
1da58fa
Merge pull request #161 from coroot/disabled_nf_conntrack
def Dec 23, 2024
8ed2571
handle partial Zookeeper reads
def Dec 23, 2024
1dbf538
Merge pull request #162 from coroot/partial_zk_reads
def Dec 25, 2024
09c1209
close existing connection with same PID:FD when creating a new one
def Dec 27, 2024
f49ea14
Merge pull request #164 from coroot/handling_out_of_order
def Dec 27, 2024
704288b
Merge remote-tracking branch 'upstream/main' into rebase-upstream-30-12
mayankpande88 Dec 30, 2024
e292d66
fix: fix for go version
mayankpande88 Dec 30, 2024
2828e1a
fix: fix for active connection metric
mayankpande88 Dec 30, 2024
82e0454
fix: fix for tracing conflict
mayankpande88 Dec 30, 2024
0919f17
fix: fix for src workload
mayankpande88 Dec 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.21'
go-version: '1.23'
- run: sudo apt install -y libsystemd-dev
- name: gofmt -l .
run: files=$(gofmt -l .); if [[ -n "$files" ]]; then echo "$files"; exit 1; fi
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Below are some basic guidelines.

## Requirements
* Linux ≥v4.16 (amd64, arm64)
* Go v1.21
* Go v1.23


## Running
Expand Down
8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.21-bullseye AS builder
FROM golang:1.23-bullseye AS builder
RUN apt update && apt install -y libsystemd-dev
WORKDIR /tmp/src
COPY go.mod .
Expand All @@ -8,7 +8,9 @@ COPY . .
ARG VERSION=unknown
RUN CGO_ENABLED=1 go build -mod=readonly -ldflags "-X main.version=$VERSION" -o coroot-node-agent .

FROM debian:bullseye-slim
RUN apt update && apt install -y ca-certificates && apt clean
FROM registry.access.redhat.com/ubi9/ubi

ARG VERSION=unknown

COPY --from=builder /tmp/src/coroot-node-agent /usr/bin/coroot-node-agent
ENTRYPOINT ["coroot-node-agent"]
2 changes: 1 addition & 1 deletion Dockerfile.alpine
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=linux/amd64 golang:1.22-alpine as build-stage
FROM --platform=linux/amd64 golang:1.23-alpine as build-stage
# Set destination for COPY
WORKDIR /app
RUN apk add --no-cache --update go gcc g++ bash git
Expand Down
54 changes: 32 additions & 22 deletions cgroup/cgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var (
containerdIdRegexp = regexp.MustCompile(`cri-containerd[-:]([a-z0-9]{64})`)
lxcIdRegexp = regexp.MustCompile(`/lxc/([^/]+)`)
systemSliceIdRegexp = regexp.MustCompile(`(/(system|runtime)\.slice/([^/]+))`)
talosIdRegexp = regexp.MustCompile(`/(system|podruntime)/([^/]+)`)
)

type Version uint8
Expand All @@ -43,6 +44,7 @@ const (
ContainerTypeLxc
ContainerTypeSystemdService
ContainerTypeSandbox
ContainerTypeTalosRuntime
)

func (t ContainerType) String() string {
Expand Down Expand Up @@ -105,24 +107,25 @@ func NewFromProcessCgroupFile(filePath string) (*Cgroup, error) {
cg.subsystems[cgType] = path.Join(baseCgroupPath, parts[2])
}
}
if p := cg.subsystems["name=systemd"]; p != "" {
cg.Id = p
cg.Version = V1
} else if p = cg.subsystems["cpu"]; p != "" {
cg.Id = p
cg.Version = V1
} else {
cg.Id = cg.subsystems[""]
if cg.Id = cg.subsystems[""]; cg.Id != "" {
cg.Version = V2
} else if cg.Id = cg.subsystems["cpu"]; cg.Id != "" {
cg.Version = V1
}
if (cg.Id == "" || cg.Id == "/") && cg.subsystems["name=systemd"] != "/" {
cg.Id = cg.subsystems["name=systemd"]
}
if cg.ContainerType, cg.ContainerId, err = containerByCgroup(cg.Id); err != nil {
return nil, err
}
return cg, nil
}

func containerByCgroup(path string) (ContainerType, string, error) {
parts := strings.Split(strings.TrimLeft(path, "/"), "/")
func containerByCgroup(cgroupPath string) (ContainerType, string, error) {
parts := strings.Split(strings.TrimLeft(cgroupPath, "/"), "/")
if cgroupPath == "/init" {
return ContainerTypeTalosRuntime, "/talos/init", nil
}
if len(parts) < 2 {
return ContainerTypeStandaloneProcess, "", nil
}
Expand All @@ -134,43 +137,50 @@ func containerByCgroup(path string) (ContainerType, string, error) {
return ContainerTypeStandaloneProcess, "", nil
}
if prefix == "docker" || (prefix == "system.slice" && strings.HasPrefix(parts[1], "docker-")) {
matches := dockerIdRegexp.FindStringSubmatch(path)
matches := dockerIdRegexp.FindStringSubmatch(cgroupPath)
if matches == nil {
return ContainerTypeUnknown, "", fmt.Errorf("invalid docker cgroup %s", path)
return ContainerTypeUnknown, "", fmt.Errorf("invalid docker cgroup %s", cgroupPath)
}
return ContainerTypeDocker, matches[1], nil
}
if strings.Contains(path, "kubepods") {
crioMatches := crioIdRegexp.FindStringSubmatch(path)
if strings.Contains(cgroupPath, "kubepods") {
crioMatches := crioIdRegexp.FindStringSubmatch(cgroupPath)
if crioMatches != nil {
return ContainerTypeCrio, crioMatches[1], nil
}
if strings.Contains(path, "crio-conmon-") {
if strings.Contains(cgroupPath, "crio-conmon-") {
return ContainerTypeUnknown, "", nil
}
containerdMatches := containerdIdRegexp.FindStringSubmatch(path)
containerdMatches := containerdIdRegexp.FindStringSubmatch(cgroupPath)
if containerdMatches != nil {
return ContainerTypeContainerd, containerdMatches[1], nil
}
matches := dockerIdRegexp.FindStringSubmatch(path)
matches := dockerIdRegexp.FindStringSubmatch(cgroupPath)
if matches == nil {
return ContainerTypeSandbox, "", nil
}
return ContainerTypeDocker, matches[1], nil
}
if prefix == "lxc" {
matches := lxcIdRegexp.FindStringSubmatch(path)
matches := lxcIdRegexp.FindStringSubmatch(cgroupPath)
if matches == nil {
return ContainerTypeUnknown, "", fmt.Errorf("invalid lxc cgroup %s", path)
return ContainerTypeUnknown, "", fmt.Errorf("invalid lxc cgroup %s", cgroupPath)
}
return ContainerTypeLxc, matches[1], nil
}
if prefix == "system" || prefix == "podruntime" {
matches := talosIdRegexp.FindStringSubmatch(cgroupPath)
if matches == nil {
return ContainerTypeUnknown, "", fmt.Errorf("invalid talos runtime cgroup %s", cgroupPath)
}
return ContainerTypeTalosRuntime, path.Join("/talos/", matches[2]), nil
}
if prefix == "system.slice" || prefix == "runtime.slice" {
matches := systemSliceIdRegexp.FindStringSubmatch(path)
matches := systemSliceIdRegexp.FindStringSubmatch(cgroupPath)
if matches == nil {
return ContainerTypeUnknown, "", fmt.Errorf("invalid systemd cgroup %s", path)
return ContainerTypeUnknown, "", fmt.Errorf("invalid systemd cgroup %s", cgroupPath)
}
return ContainerTypeSystemdService, strings.Replace(matches[1], "\\x2d", "-", -1), nil
}
return ContainerTypeUnknown, "", fmt.Errorf("unknown container: %s", path)
return ContainerTypeUnknown, "", fmt.Errorf("unknown container: %s", cgroupPath)
}
41 changes: 41 additions & 0 deletions cgroup/cgroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ func TestNewFromProcessCgroupFile(t *testing.T) {
assert.Equal(t, "/system.slice/springboot.service", cg.ContainerId)
assert.Equal(t, ContainerTypeSystemdService, cg.ContainerType)

cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/700/cgroup"))
assert.Nil(t, err)
assert.Equal(t, V2, cg.Version)
assert.Equal(t, "/podruntime/runtime", cg.Id)
assert.Equal(t, "/talos/runtime", cg.ContainerId)
assert.Equal(t, ContainerTypeTalosRuntime, cg.ContainerType)

cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/800/cgroup"))
assert.Nil(t, err)
assert.Equal(t, V2, cg.Version)
assert.Equal(t, "/system.slice/docker-cf87ba651579c9231db817909e7865e5747bd7abcac0c57ce23cf4abbaee046b.scope", cg.Id)
assert.Equal(t, "cf87ba651579c9231db817909e7865e5747bd7abcac0c57ce23cf4abbaee046b", cg.ContainerId)
assert.Equal(t, ContainerTypeDocker, cg.ContainerType)

cg, err = NewFromProcessCgroupFile(path.Join("fixtures/proc/900/cgroup"))
assert.Nil(t, err)
assert.Equal(t, V1, cg.Version)
assert.Equal(t, "/system.slice/python-app.service", cg.Id)
assert.Equal(t, "/system.slice/python-app.service", cg.ContainerId)
assert.Equal(t, ContainerTypeSystemdService, cg.ContainerType)

baseCgroupPath = "/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podc83d0428_58af_41eb_8dba_b9e6eddffe7b.slice/docker-0e612005fd07e7f47e2cd07df99a2b4e909446814d71d0b5e4efc7159dd51252.scope"
defer func() {
baseCgroupPath = ""
Expand Down Expand Up @@ -97,6 +118,11 @@ func TestContainerByCgroup(t *testing.T) {
as.Equal("63425c4a8b4291744a79dd9011fddc7a1f8ffda61f65d72196aa01d00cae2e2d", id)
as.Nil(err)

typ, id, err = containerByCgroup("/docker/63425c4a8b4291744a79dd9011fddc7a1f8ffda61f65d72196aa01d00cae2e2d")
as.Equal(typ, ContainerTypeDocker)
as.Equal("63425c4a8b4291744a79dd9011fddc7a1f8ffda61f65d72196aa01d00cae2e2d", id)
as.Nil(err)

typ, id, err = containerByCgroup("/lxc/mysql-primary-db")
as.Equal(typ, ContainerTypeLxc)
as.Equal("mysql-primary-db", id)
Expand Down Expand Up @@ -136,4 +162,19 @@ func TestContainerByCgroup(t *testing.T) {
as.Equal(typ, ContainerTypeContainerd)
as.Equal("d4a9f9195eaf7e4a729f24151101e1de61f1398677e7b82acfb936dff0b4ce55", id)
as.Nil(err)

typ, id, err = containerByCgroup("/podruntime/kubelet")
as.Equal(typ, ContainerTypeTalosRuntime)
as.Equal("/talos/kubelet", id)
as.Nil(err)

typ, id, err = containerByCgroup("/system/dashboard")
as.Equal(typ, ContainerTypeTalosRuntime)
as.Equal("/talos/dashboard", id)
as.Nil(err)

typ, id, err = containerByCgroup("/init")
as.Equal(typ, ContainerTypeTalosRuntime)
as.Equal("/talos/init", id)
as.Nil(err)
}
19 changes: 13 additions & 6 deletions cgroup/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"path"
"strconv"
"strings"

"github.com/coroot/coroot-node-agent/common"
)

type CPUStat struct {
Expand All @@ -14,27 +16,32 @@ type CPUStat struct {
LimitCores float64
}

func (cg Cgroup) CpuStat() (*CPUStat, error) {
func (cg Cgroup) CpuStat() *CPUStat {
if cg.Version == V1 {
return cg.cpuStatV1()
st, _ := cg.cpuStatV1()
return st
}
return cg.cpuStatV2()
st, _ := cg.cpuStatV2()
return st
}

func (cg Cgroup) cpuStatV1() (*CPUStat, error) {
if cg.subsystems["cpu"] == "/" || cg.subsystems["cpuacct"] == "/" {
return nil, nil
}
throttling, err := readVariablesFromFile(path.Join(cgRoot, "cpu", cg.subsystems["cpu"], "cpu.stat"))
if err != nil {
return nil, err
}
usageNs, err := readIntFromFile(path.Join(cgRoot, "cpuacct", cg.subsystems["cpuacct"], "cpuacct.usage"))
usageNs, err := common.ReadIntFromFile(path.Join(cgRoot, "cpuacct", cg.subsystems["cpuacct"], "cpuacct.usage"))
if err != nil {
return nil, err
}
periodUs, err := readIntFromFile(path.Join(cgRoot, "cpu", cg.subsystems["cpu"], "cpu.cfs_period_us"))
periodUs, err := common.ReadIntFromFile(path.Join(cgRoot, "cpu", cg.subsystems["cpu"], "cpu.cfs_period_us"))
if err != nil {
return nil, err
}
quotaUs, err := readIntFromFile(path.Join(cgRoot, "cpu", cg.subsystems["cpu"], "cpu.cfs_quota_us"))
quotaUs, err := common.ReadIntFromFile(path.Join(cgRoot, "cpu", cg.subsystems["cpu"], "cpu.cfs_quota_us"))
if err != nil {
return nil, err
}
Expand Down
17 changes: 9 additions & 8 deletions cgroup/cpu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,29 @@ func TestCgroup_CpuStat(t *testing.T) {
cgRoot = "fixtures/cgroup"

cg, _ := NewFromProcessCgroupFile(path.Join("fixtures/proc/100/cgroup"))
s, err := cg.CpuStat()
assert.Nil(t, err)
s := cg.CpuStat()
assert.Equal(t, 0., s.LimitCores)
assert.Equal(t, 26778.913419246, s.UsageSeconds)

cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/200/cgroup"))
s, err = cg.CpuStat()
assert.Nil(t, err)
s = cg.CpuStat()
assert.Equal(t, 1.5, s.LimitCores)
assert.Equal(t, 254005.032764376, s.ThrottledTimeSeconds)

cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/400/cgroup"))
s, err = cg.CpuStat()
assert.Nil(t, err)
s = cg.CpuStat()
assert.Equal(t, 0.1, s.LimitCores)
assert.Equal(t, 0.363166, s.ThrottledTimeSeconds)
assert.Equal(t, 3795.681254, s.UsageSeconds)

cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/500/cgroup"))
s, err = cg.CpuStat()
assert.Nil(t, err)
s = cg.CpuStat()
assert.Equal(t, 0., s.LimitCores)
assert.Equal(t, 0., s.ThrottledTimeSeconds)
assert.Equal(t, 5531.521992, s.UsageSeconds)

cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/1000/cgroup"))
s, err := cg.cpuStatV1()
assert.NoError(t, err)
assert.Nil(t, s)
}
11 changes: 11 additions & 0 deletions cgroup/fixtures/proc/1000/cgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
11:pids:/
10:blkio:/
9:net_cls,net_prio:/
8:perf_event:/
7:freezer:/
6:memory:/
5:cpu,cpuacct:/
4:hugetlb:/
3:cpuset:/
2:devices:/system.slice/system-getty.slice
1:name=systemd:/system.slice/system-getty.slice/getty@tty1.service
1 change: 1 addition & 0 deletions cgroup/fixtures/proc/700/cgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0::/podruntime/runtime
2 changes: 2 additions & 0 deletions cgroup/fixtures/proc/800/cgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1:name=systemd:/
0::/system.slice/docker-cf87ba651579c9231db817909e7865e5747bd7abcac0c57ce23cf4abbaee046b.scope
2 changes: 2 additions & 0 deletions cgroup/fixtures/proc/900/cgroup
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1:name=systemd:/system.slice/python-app.service
7:cpu,cpuacct:/
11 changes: 8 additions & 3 deletions cgroup/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ type IOStat struct {
WrittenBytes uint64
}

func (cg *Cgroup) IOStat() (map[string]IOStat, error) {
func (cg *Cgroup) IOStat() map[string]IOStat {
if cg.Version == V1 {
return cg.ioStatV1()
st, _ := cg.ioStatV1()
return st
}
return cg.ioStatV2()
st, _ := cg.ioStatV2()
return st
}

func (cg *Cgroup) ioStatV1() (map[string]IOStat, error) {
if cg.subsystems["blkio"] == "/" {
return nil, nil
}
ops, err := readBlkioStatFile(path.Join(cgRoot, "blkio", cg.subsystems["blkio"], "blkio.throttle.io_serviced"))
if err != nil {
return nil, err
Expand Down
10 changes: 6 additions & 4 deletions cgroup/io_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ func TestCgroup_IOStat(t *testing.T) {
cgRoot = "fixtures/cgroup"

cg, _ := NewFromProcessCgroupFile(path.Join("fixtures/proc/200/cgroup"))
stat, err := cg.IOStat()
assert.Nil(t, err)
stat := cg.IOStat()
assert.Equal(t,
map[string]IOStat{
"8:0": {ReadOps: 0, WriteOps: 281, ReadBytes: 0, WrittenBytes: 4603904},
Expand All @@ -24,13 +23,16 @@ func TestCgroup_IOStat(t *testing.T) {
stat)

cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/400/cgroup"))
stat, err = cg.IOStat()
assert.Nil(t, err)
stat = cg.IOStat()
assert.Equal(t,
map[string]IOStat{
"252:0": {ReadOps: 22, WriteOps: 57111, ReadBytes: 11, WrittenBytes: 630538240},
"253:0": {ReadOps: 44, WriteOps: 57056, ReadBytes: 33, WrittenBytes: 630538241},
},
stat)

cg, _ = NewFromProcessCgroupFile(path.Join("fixtures/proc/1000/cgroup"))
stat, err := cg.ioStatV1()
assert.NoError(t, err)
assert.Nil(t, stat)
}
Loading