-
+
{{ label }}
{{ mouseOver ? (selectedPoint?.value ?? selectedPoint?.y ?? statValue) : statValue }}
+ / {{ limit }}
diff --git a/assets/components/LogViewer/StatSparkline.vue b/assets/components/LogViewer/StatSparkline.vue
index e7ed0c1e..7cf8d15a 100644
--- a/assets/components/LogViewer/StatSparkline.vue
+++ b/assets/components/LogViewer/StatSparkline.vue
@@ -11,7 +11,7 @@ import { scaleLinear } from "d3-scale";
import { area, curveStep } from "d3-shape";
const d3 = { extent, scaleLinear, area, curveStep };
-const { data, width = 150, height = 30 } = defineProps<{ data: Point
[]; width?: number; height?: number }>();
+const { data, width = 175, height = 30 } = defineProps<{ data: Point[]; width?: number; height?: number }>();
const x = d3.scaleLinear().range([0, width]);
const y = d3.scaleLinear().range([height, 0]);
diff --git a/assets/models/Container.ts b/assets/models/Container.ts
index ff701563..73d35c8b 100644
--- a/assets/models/Container.ts
+++ b/assets/models/Container.ts
@@ -38,6 +38,8 @@ export class Container {
public readonly host: string,
public readonly labels = {} as Record,
public state: ContainerState,
+ public readonly cpuLimit: number,
+ public readonly memoryLimit: number,
stats: Stat[],
public readonly group?: string,
public health?: ContainerHealth,
diff --git a/assets/stores/container.ts b/assets/stores/container.ts
index 10ddee35..8c7e97d0 100644
--- a/assets/stores/container.ts
+++ b/assets/stores/container.ts
@@ -154,6 +154,8 @@ export const useContainerStore = defineStore("container", () => {
c.host,
c.labels,
c.state,
+ c.cpuLimit,
+ c.memoryLimit,
c.stats,
c.group,
c.health,
diff --git a/assets/types/Container.d.ts b/assets/types/Container.d.ts
index 4639e69a..9d6ddb5e 100644
--- a/assets/types/Container.d.ts
+++ b/assets/types/Container.d.ts
@@ -16,6 +16,8 @@ export type ContainerJson = {
readonly status: string;
readonly state: ContainerState;
readonly host: string;
+ readonly cpuLimit: number;
+ readonly memoryLimit: number;
readonly labels: Record;
readonly stats: ContainerStat[];
readonly health?: ContainerHealth;
diff --git a/assets/utils/index.ts b/assets/utils/index.ts
index b9c328ca..70e1753b 100644
--- a/assets/utils/index.ts
+++ b/assets/utils/index.ts
@@ -1,10 +1,19 @@
-export function formatBytes(bytes: number, decimals = 2) {
+export function formatBytes(
+ bytes: number,
+ { decimals = 2, short = false }: { decimals?: number; short?: boolean } = { decimals: 2, short: false },
+) {
if (bytes === 0) return "0 Bytes";
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
- return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
+
+ const value = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
+ if (short) {
+ return value + sizes[i].charAt(0);
+ } else {
+ return value + " " + sizes[i];
+ }
}
export function getDeep(obj: Record, path: string[]) {
diff --git a/internal/container/types.go b/internal/container/types.go
index 8f94e31a..afefe288 100644
--- a/internal/container/types.go
+++ b/internal/container/types.go
@@ -24,6 +24,8 @@ type Container struct {
Tty bool `json:"-"`
Labels map[string]string `json:"labels,omitempty"`
Stats *utils.RingBuffer[ContainerStat] `json:"stats,omitempty"`
+ MemoryLimit int64 `json:"memoryLimit"`
+ CPULimit float64 `json:"cpuLimit"`
Group string `json:"group,omitempty"`
FullyLoaded bool `json:"-,omitempty"`
}
@@ -54,7 +56,7 @@ func ParseContainerFilter(commaValues string) (ContainerLabels, error) {
return filter, nil
}
- for _, val := range strings.Split(commaValues, ",") {
+ for val := range strings.SplitSeq(commaValues, ",") {
pos := strings.Index(val, "=")
if pos == -1 {
return nil, fmt.Errorf("invalid filter: %s", filter)
diff --git a/internal/docker/client.go b/internal/docker/client.go
index 2dac4b4a..f27b76bc 100644
--- a/internal/docker/client.go
+++ b/internal/docker/client.go
@@ -388,6 +388,11 @@ func newContainerFromJSON(c docker.InspectResponse, host string) container.Conta
group = c.Config.Labels["dev.dozzle.group"]
}
+ CPULimit := float64(0)
+ if c.HostConfig.CPUPeriod > 0 {
+ CPULimit = float64(c.HostConfig.CPUQuota) / float64(c.HostConfig.CPUPeriod)
+ }
+
container := container.Container{
ID: c.ID[:12],
Name: name,
@@ -399,6 +404,8 @@ func newContainerFromJSON(c docker.InspectResponse, host string) container.Conta
Stats: utils.NewRingBuffer[container.ContainerStat](300), // 300 seconds of stats
Group: group,
Tty: c.Config.Tty,
+ MemoryLimit: c.HostConfig.Memory,
+ CPULimit: CPULimit,
FullyLoaded: true,
}
diff --git a/internal/docker/client_test.go b/internal/docker/client_test.go
index 36c8b221..70c14d08 100644
--- a/internal/docker/client_test.go
+++ b/internal/docker/client_test.go
@@ -184,7 +184,11 @@ func Test_dockerClient_FindContainer_happy(t *testing.T) {
proxy := new(mockedProxy)
state := &docker.State{Status: "running", StartedAt: time.Now().Format(time.RFC3339Nano)}
- json := docker.InspectResponse{ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijklmnopqrst", State: state}, Config: &docker.Config{Tty: false}}
+
+ json := docker.InspectResponse{
+ ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijklmnopqrst", State: state, HostConfig: &docker.HostConfig{}},
+ Config: &docker.Config{Tty: false},
+ }
proxy.On("ContainerInspect", mock.Anything, "abcdefghijkl").Return(json, nil)
client := &DockerClient{proxy, container.Host{ID: "localhost"}, system.Info{}}
@@ -213,7 +217,7 @@ func Test_dockerClient_ContainerActions_happy(t *testing.T) {
client := &DockerClient{proxy, container.Host{ID: "localhost"}, system.Info{}}
state := &docker.State{Status: "running", StartedAt: time.Now().Format(time.RFC3339Nano)}
- json := docker.InspectResponse{ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijkl", State: state}, Config: &docker.Config{Tty: false}}
+ json := docker.InspectResponse{ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijkl", State: state, HostConfig: &docker.HostConfig{}}, Config: &docker.Config{Tty: false}}
proxy.On("ContainerInspect", mock.Anything, "abcdefghijkl").Return(json, nil)
proxy.On("ContainerStart", mock.Anything, "abcdefghijkl", mock.Anything).Return(nil)