Repository: lf-edge/eve-tools
Pull request #11: Initial proto objects for metric server hosted in a runtime app instance
Author: login: andrewd-zededa
Created: 2025-03-06T18:16:43Z | Merged: 2025-03-20T22:02:27Z

A webserver may be deployed inside an eve app instance which hosts
http endpoints returning nested application instance metrics.
These objects are returned in the body of the http GET so that
eve knows which application instance ids are running nested
inside the runtime and the metrics for each of those respective
nested app instances.
   
Webserver api docs are in progress.


Diff:
diff --git a/.yetus/excludes.txt b/.yetus/excludes.txt
new file mode 100644
index 0000000..74b9b1d
--- /dev/null
+++ b/.yetus/excludes.txt
@@ -0,0 +1,10 @@
+yetus-output/*
+CONTRIBUTING.md
+Dockerfile
+.gitmodules
+INSTALL.md
+README.md
+azure-iot-edge-on-eve/*
+azure-on-eve/*
+eve-tpm-tools/*
+guest-improvements/*
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3cdd8c5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
+yetus:
+	@echo Running yetus
+	rm -rf yetus-output/*
+	mkdir -p yetus-output
+	docker run --rm -v $(CURDIR):/src:delegated,z ghcr.io/apache/yetus:0.15.0 \
+		--basedir=/src \
+		--test-parallel=true \
+		--dirty-workspace \
+		--empty-patch \
+		--plugins=all \
+		--patch-dir=/src/yetus-output
\ No newline at end of file
diff --git a/runtimemetrics/Dockerfile b/runtimemetrics/Dockerfile
new file mode 100644
index 0000000..20594e7
--- /dev/null
+++ b/runtimemetrics/Dockerfile
@@ -0,0 +1,24 @@
+# syntax=docker/dockerfile:1.6.0
+FROM alpine:3.21
+
+ARG TARGETOS=linux
+ARG TARGETARCH
+ARG PROTOC_GEN_GO_VERSION=1.31.0
+ARG PROTOC_VERSION=23.4
+
+RUN apk add --no-cache bash curl git go make
+
+RUN arch=$(uname -m); \
+  # If the third to last character is not an underscore, insert an underscore in the `arch` variable
+  if [ "${arch: -3:1}" != "_" ]; then \
+    arch="${arch%??}_${arch: -2:2}"; \
+  fi; \
+  curl -fsSL -o protobuf.zip https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-${TARGETOS}-${arch}.zip; \
+  unzip protobuf.zip -d /usr/local; \
+  rm -f protobuf.zip
+
+RUN git clone https://github.com/seamia/protodot.git /protodot
+RUN go build -C /protodot -o /usr/local/bin/protodot .
+
+RUN mkdir -p $(go env GOPATH)
+RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v${PROTOC_GEN_GO_VERSION} && mv /root/go/bin/protoc-gen-go /usr/local/bin/protoc-gen-go
diff --git a/runtimemetrics/Makefile b/runtimemetrics/Makefile
new file mode 100644
index 0000000..0bcc870
--- /dev/null
+++ b/runtimemetrics/Makefile
@@ -0,0 +1,29 @@
+proto-container-build:
+	docker build -f Dockerfile -t runtimemetrics-builder .
+
+gen-go:
+	docker run --rm --env HOME=/src -v $(PWD):/src -w /src -u $$(id -u) runtimemetrics-builder make proto
+
+.PHONY: proto-api-% proto proto-container-build gen-go
+
+# Target run in runtimemetrics-builder 'proto-container-build'
+proto: go
+	@echo Done building protobuf, you may want to vendor it into your projects, e.g. lf-edge/eve.
+	@echo See ./go/README.md for more information.
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+go: PROTOC_OUT_OPTS=paths=source_relative:
+go: proto-api-go
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+proto-api-%:
+	rm -rf $*/*/; mkdir -p $* # building $@
+	protoc -I./proto --$(*)_out=$(PROTOC_OUT_OPTS)./$* proto/*/*.proto
+
+help:
+	@echo "runtimemetrics contains proto objects to generate structures for the webserver running inside an"
+	@echo "	eve runtime vm which reports nested app instance metrics"
+	@echo
+	@echo "Commonly used maintenance and development targets:"
+	@echo "   proto-container-build      if you have not built this repo before, build the container"
+	@echo "   gen-go                     to build and output go objects"
\ No newline at end of file
diff --git a/runtimemetrics/README.md b/runtimemetrics/README.md
new file mode 100644
index 0000000..051c884
--- /dev/null
+++ b/runtimemetrics/README.md
@@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on EVE which returns metric data to EVE for containers or groups
+of containers which reside in the runtime.  This runtime can be a VM and
+is expected to be running inside an EVE AppInstance.
+The server listens on the address defined by CollectStatsIPAddr in app
+instance config, this address will be on an airgapped local network
+instance with no external access outside of EVE.  The consumer of this
+data is in the pillar service container in EVE-OS.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime
+metric server. All endpoints will start with an api prefix path "/api/v1/"
+until further versions are defined. All endpoints are accessible over
+http at tcp port 57475.
+
+### Inventory
+
+GET /api/v1/inventory/nested-app-id
+
+Return codes:
+
+* Inventory Returned: `200`
+* Non-GET type request: `405`
+
+Response:
+
+The body will contain the NestedAppInventory structure in json form.
+
+### Metrics
+
+GET /api/v1/metrics/nested-app-id/<app-id>
+
+Return codes:
+
+* Metrics returned: `200`
+* App Id not in uuid format: `400`
+* App Id not defined in runtime: `404`
+* Non-GET type request: `405`
+
+Response:
+
+The body will contain the NestedAppMetrics structure in json form.
diff --git a/runtimemetrics/go/go.mod b/runtimemetrics/go/go.mod
new file mode 100644
index 0000000..12bab91
--- /dev/null
+++ b/runtimemetrics/go/go.mod
@@ -0,0 +1,3 @@
+module github.com/lf-edge/eve-tools/runtimemetrics/go
+
+go 1.22.2
diff --git a/runtimemetrics/go/nestedappinstancemetrics/nestedappinstanceinventory.pb.go b/runtimemetrics/go/nestedappinstancemetrics/nestedappinstanceinventory.pb.go
new file mode 100644
index 0000000..c6257f9
--- /dev/null
+++ b/runtimemetrics/go/nestedappinstancemetrics/nestedappinstanceinventory.pb.go
@@ -0,0 +1,253 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.31.0
+// 	protoc        v4.23.4
+// source: nestedappinstancemetrics/nestedappinstanceinventory.proto
+
+package nestedappinstancemetrics
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// NestedAppStatus is a DomainStatus structure
+// for the Nested App.
+// intended for EVE logging infrastructure to
+// consume and separate runtime log entries for each
+// app instance running inside a runtime and logging
+// to the console.
+type NestedAppStatus struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// App Id of the nested app inside the runtime
+	AppId string `protobuf:"bytes,1,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"`
+	// App Name is the app instance display name
+	AppName string `protobuf:"bytes,2,opt,name=app_name,json=appName,proto3" json:"app_name,omitempty"`
+	// Logging has been disabled in the runtime
+	// for this nested app instance inside the runtime
+	DisableLogs bool `protobuf:"varint,3,opt,name=disable_logs,json=disableLogs,proto3" json:"disable_logs,omitempty"`
+}
+
+func (x *NestedAppStatus) Reset() {
+	*x = NestedAppStatus{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NestedAppStatus) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NestedAppStatus) ProtoMessage() {}
+
+func (x *NestedAppStatus) ProtoReflect() protoreflect.Message {
+	mi := &file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NestedAppStatus.ProtoReflect.Descriptor instead.
+func (*NestedAppStatus) Descriptor() ([]byte, []int) {
+	return file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *NestedAppStatus) GetAppId() string {
+	if x != nil {
+		return x.AppId
+	}
+	return ""
+}
+
+func (x *NestedAppStatus) GetAppName() string {
+	if x != nil {
+		return x.AppName
+	}
+	return ""
+}
+
+func (x *NestedAppStatus) GetDisableLogs() bool {
+	if x != nil {
+		return x.DisableLogs
+	}
+	return false
+}
+
+// Inventory object returned via an http server
+// running inside a nested app instance runtime on eve.
+type NestedAppInventory struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// UUIDs of the nested/virtual AppInstances as provided to the agent
+	// in the Patch Envelope Config
+	Apps []*NestedAppStatus `protobuf:"bytes,1,rep,name=apps,proto3" json:"apps,omitempty"`
+}
+
+func (x *NestedAppInventory) Reset() {
+	*x = NestedAppInventory{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NestedAppInventory) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NestedAppInventory) ProtoMessage() {}
+
+func (x *NestedAppInventory) ProtoReflect() protoreflect.Message {
+	mi := &file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NestedAppInventory.ProtoReflect.Descriptor instead.
+func (*NestedAppInventory) Descriptor() ([]byte, []int) {
+	return file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *NestedAppInventory) GetApps() []*NestedAppStatus {
+	if x != nil {
+		return x.Apps
+	}
+	return nil
+}
+
+var File_nestedappinstancemetrics_nestedappinstanceinventory_proto protoreflect.FileDescriptor
+
+var file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDesc = []byte{
+	0x0a, 0x39, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61,
+	0x6e, 0x63, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6e, 0x65, 0x73, 0x74, 0x65,
+	0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x69, 0x6e, 0x76, 0x65,
+	0x6e, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x6f, 0x72, 0x67,
+	0x2e, 0x6c, 0x66, 0x65, 0x64, 0x67, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c,
+	0x73, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+	0x22, 0x66, 0x0a, 0x0f, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x70, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x70, 0x70, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70,
+	0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70,
+	0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
+	0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x69, 0x73,
+	0x61, 0x62, 0x6c, 0x65, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x5e, 0x0a, 0x12, 0x4e, 0x65, 0x73, 0x74,
+	0x65, 0x64, 0x41, 0x70, 0x70, 0x49, 0x6e, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x48,
+	0x0a, 0x04, 0x61, 0x70, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x6f,
+	0x72, 0x67, 0x2e, 0x6c, 0x66, 0x65, 0x64, 0x67, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x2e, 0x74, 0x6f,
+	0x6f, 0x6c, 0x73, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x52, 0x04, 0x61, 0x70, 0x70, 0x73, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69, 0x74, 0x68,
+	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x66, 0x2d, 0x65, 0x64, 0x67, 0x65, 0x2f, 0x65,
+	0x76, 0x65, 0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x6e, 0x65, 0x73, 0x74, 0x65,
+	0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescOnce sync.Once
+	file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescData = file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDesc
+)
+
+func file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescGZIP() []byte {
+	file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescOnce.Do(func() {
+		file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescData = protoimpl.X.CompressGZIP(file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescData)
+	})
+	return file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDescData
+}
+
+var file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_nestedappinstancemetrics_nestedappinstanceinventory_proto_goTypes = []interface{}{
+	(*NestedAppStatus)(nil),    // 0: org.lfedge.eve.tools.runtimemetrics.NestedAppStatus
+	(*NestedAppInventory)(nil), // 1: org.lfedge.eve.tools.runtimemetrics.NestedAppInventory
+}
+var file_nestedappinstancemetrics_nestedappinstanceinventory_proto_depIdxs = []int32{
+	0, // 0: org.lfedge.eve.tools.runtimemetrics.NestedAppInventory.apps:type_name -> org.lfedge.eve.tools.runtimemetrics.NestedAppStatus
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_nestedappinstancemetrics_nestedappinstanceinventory_proto_init() }
+func file_nestedappinstancemetrics_nestedappinstanceinventory_proto_init() {
+	if File_nestedappinstancemetrics_nestedappinstanceinventory_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*NestedAppStatus); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*NestedAppInventory); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_nestedappinstancemetrics_nestedappinstanceinventory_proto_goTypes,
+		DependencyIndexes: file_nestedappinstancemetrics_nestedappinstanceinventory_proto_depIdxs,
+		MessageInfos:      file_nestedappinstancemetrics_nestedappinstanceinventory_proto_msgTypes,
+	}.Build()
+	File_nestedappinstancemetrics_nestedappinstanceinventory_proto = out.File
+	file_nestedappinstancemetrics_nestedappinstanceinventory_proto_rawDesc = nil
+	file_nestedappinstancemetrics_nestedappinstanceinventory_proto_goTypes = nil
+	file_nestedappinstancemetrics_nestedappinstanceinventory_proto_depIdxs = nil
+}
diff --git a/runtimemetrics/go/nestedappinstancemetrics/nestedappinstancelog.pb.go b/runtimemetrics/go/nestedappinstancemetrics/nestedappinstancelog.pb.go
new file mode 100644
index 0000000..a73d50c
--- /dev/null
+++ b/runtimemetrics/go/nestedappinstancemetrics/nestedappinstancelog.pb.go
@@ -0,0 +1,181 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.31.0
+// 	protoc        v4.23.4
+// source: nestedappinstancemetrics/nestedappinstancelog.proto
+
+package nestedappinstancemetrics
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+type NestedAppInstanceLogMsg struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// AppId of the nested app instance / virtual app instance
+	// eg. docker compose app instance ID
+	NestedAppId string `protobuf:"bytes,1,opt,name=nested_app_id,json=nestedAppId,proto3" json:"nested_app_id,omitempty"`
+	// container_name is the shortened name of the container.
+	// eg. compose app container name is project_name-service-replica
+	// this field should contain the service-replica suffix.
+	ContainerName string `protobuf:"bytes,2,opt,name=container_name,json=containerName,proto3" json:"container_name,omitempty"`
+	// msg is the original log from the runtime container
+	Msg string `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
+}
+
+func (x *NestedAppInstanceLogMsg) Reset() {
+	*x = NestedAppInstanceLogMsg{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_nestedappinstancemetrics_nestedappinstancelog_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NestedAppInstanceLogMsg) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NestedAppInstanceLogMsg) ProtoMessage() {}
+
+func (x *NestedAppInstanceLogMsg) ProtoReflect() protoreflect.Message {
+	mi := &file_nestedappinstancemetrics_nestedappinstancelog_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NestedAppInstanceLogMsg.ProtoReflect.Descriptor instead.
+func (*NestedAppInstanceLogMsg) Descriptor() ([]byte, []int) {
+	return file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *NestedAppInstanceLogMsg) GetNestedAppId() string {
+	if x != nil {
+		return x.NestedAppId
+	}
+	return ""
+}
+
+func (x *NestedAppInstanceLogMsg) GetContainerName() string {
+	if x != nil {
+		return x.ContainerName
+	}
+	return ""
+}
+
+func (x *NestedAppInstanceLogMsg) GetMsg() string {
+	if x != nil {
+		return x.Msg
+	}
+	return ""
+}
+
+var File_nestedappinstancemetrics_nestedappinstancelog_proto protoreflect.FileDescriptor
+
+var file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDesc = []byte{
+	0x0a, 0x33, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61,
+	0x6e, 0x63, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6e, 0x65, 0x73, 0x74, 0x65,
+	0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6f, 0x67, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x6f, 0x72, 0x67, 0x2e, 0x6c, 0x66, 0x65, 0x64, 0x67,
+	0x65, 0x2e, 0x65, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e, 0x72, 0x75, 0x6e, 0x74,
+	0x69, 0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x76, 0x0a, 0x17, 0x4e, 0x65,
+	0x73, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4c,
+	0x6f, 0x67, 0x4d, 0x73, 0x67, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f,
+	0x61, 0x70, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65,
+	0x73, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e,
+	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,
+	0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d,
+	0x73, 0x67, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2f, 0x6c, 0x66, 0x2d, 0x65, 0x64, 0x67, 0x65, 0x2f, 0x65, 0x76, 0x65, 0x2d, 0x74, 0x6f, 0x6f,
+	0x6c, 0x73, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x61, 0x70, 0x70, 0x69, 0x6e,
+	0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescOnce sync.Once
+	file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescData = file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDesc
+)
+
+func file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescGZIP() []byte {
+	file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescOnce.Do(func() {
+		file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescData = protoimpl.X.CompressGZIP(file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescData)
+	})
+	return file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDescData
+}
+
+var file_nestedappinstancemetrics_nestedappinstancelog_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_nestedappinstancemetrics_nestedappinstancelog_proto_goTypes = []interface{}{
+	(*NestedAppInstanceLogMsg)(nil), // 0: org.lfedge.eve.tools.runtimemetrics.NestedAppInstanceLogMsg
+}
+var file_nestedappinstancemetrics_nestedappinstancelog_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_nestedappinstancemetrics_nestedappinstancelog_proto_init() }
+func file_nestedappinstancemetrics_nestedappinstancelog_proto_init() {
+	if File_nestedappinstancemetrics_nestedappinstancelog_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_nestedappinstancemetrics_nestedappinstancelog_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*NestedAppInstanceLogMsg); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_nestedappinstancemetrics_nestedappinstancelog_proto_goTypes,
+		DependencyIndexes: file_nestedappinstancemetrics_nestedappinstancelog_proto_depIdxs,
+		MessageInfos:      file_nestedappinstancemetrics_nestedappinstancelog_proto_msgTypes,
+	}.Build()
+	File_nestedappinstancemetrics_nestedappinstancelog_proto = out.File
+	file_nestedappinstancemetrics_nestedappinstancelog_proto_rawDesc = nil
+	file_nestedappinstancemetrics_nestedappinstancelog_proto_goTypes = nil
+	file_nestedappinstancemetrics_nestedappinstancelog_proto_depIdxs = nil
+}
diff --git a/runtimemetrics/go/nestedappinstancemetrics/nestedappinstancemetrics.pb.go b/runtimemetrics/go/nestedappinstancemetrics/nestedappinstancemetrics.pb.go
new file mode 100644
index 0000000..a527f53
--- /dev/null
+++ b/runtimemetrics/go/nestedappinstancemetrics/nestedappinstancemetrics.pb.go
@@ -0,0 +1,291 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.31.0
+// 	protoc        v4.23.4
+// source: nestedappinstancemetrics/nestedappinstancemetrics.proto
+
+package nestedappinstancemetrics
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// NestedAppMetrics object to serve as a metric
+// for a top level appinstance and all containers
+// inside an app instance.  A single parent NestedAppMetrics returned from
+// GET /api/v1/metrics/nested-app-id/<app-id>
+type NestedAppMetrics struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The parent NestedAppMetrics.Id will have an app instance uuid
+	// to show app level metrics where the app is a group of one or more containers.
+	// The child_container_metrics NestedAppMetrics.Id will have a container id
+	// where the prefix matches the parent id.
+	Id     string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // uptime, pause, stop status
+	Pids   uint32 `protobuf:"varint,3,opt,name=Pids,proto3" json:"Pids,omitempty"`    // number of PIDs within the container
+	// CPU stats
+	Uptime         int64  `protobuf:"varint,4,opt,name=uptime,proto3" json:"uptime,omitempty"`                 // unix.nano, time since container starts
+	CPUTotal       uint64 `protobuf:"varint,5,opt,name=CPUTotal,proto3" json:"CPUTotal,omitempty"`             // container CPU since starts in nanosec
+	SystemCPUTotal uint64 `protobuf:"varint,6,opt,name=SystemCPUTotal,proto3" json:"SystemCPUTotal,omitempty"` // total system, user, idle in nanosec
+	// Memory stats
+	UsedMem      uint32 `protobuf:"varint,7,opt,name=UsedMem,proto3" json:"UsedMem,omitempty"`           // in MBytes
+	AllocatedMem uint32 `protobuf:"varint,8,opt,name=AllocatedMem,proto3" json:"AllocatedMem,omitempty"` // in MBytes
+	// Network stats
+	TxBytes uint64 `protobuf:"varint,9,opt,name=TxBytes,proto3" json:"TxBytes,omitempty"`  // in Bytes
+	RxBytes uint64 `protobuf:"varint,10,opt,name=RxBytes,proto3" json:"RxBytes,omitempty"` // in Bytes
+	// Disk stats
+	ReadBytes  uint64 `protobuf:"varint,11,opt,name=ReadBytes,proto3" json:"ReadBytes,omitempty"`   // in MBytes
+	WriteBytes uint64 `protobuf:"varint,12,opt,name=WriteBytes,proto3" json:"WriteBytes,omitempty"` // in MBytes
+	// Child container metrics
+	// id field should be a container name where the prefix
+	// is the app instance id / above parent id.
+	// For a compose app these id fields will be '<appid>-<service>-<replica>'
+	ChildContainerMetrics []*NestedAppMetrics `protobuf:"bytes,13,rep,name=child_container_metrics,json=childContainerMetrics,proto3" json:"child_container_metrics,omitempty"`
+}
+
+func (x *NestedAppMetrics) Reset() {
+	*x = NestedAppMetrics{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_nestedappinstancemetrics_nestedappinstancemetrics_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NestedAppMetrics) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NestedAppMetrics) ProtoMessage() {}
+
+func (x *NestedAppMetrics) ProtoReflect() protoreflect.Message {
+	mi := &file_nestedappinstancemetrics_nestedappinstancemetrics_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NestedAppMetrics.ProtoReflect.Descriptor instead.
+func (*NestedAppMetrics) Descriptor() ([]byte, []int) {
+	return file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *NestedAppMetrics) GetId() string {
+	if x != nil {
+		return x.Id
+	}
+	return ""
+}
+
+func (x *NestedAppMetrics) GetStatus() string {
+	if x != nil {
+		return x.Status
+	}
+	return ""
+}
+
+func (x *NestedAppMetrics) GetPids() uint32 {
+	if x != nil {
+		return x.Pids
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetUptime() int64 {
+	if x != nil {
+		return x.Uptime
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetCPUTotal() uint64 {
+	if x != nil {
+		return x.CPUTotal
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetSystemCPUTotal() uint64 {
+	if x != nil {
+		return x.SystemCPUTotal
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetUsedMem() uint32 {
+	if x != nil {
+		return x.UsedMem
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetAllocatedMem() uint32 {
+	if x != nil {
+		return x.AllocatedMem
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetTxBytes() uint64 {
+	if x != nil {
+		return x.TxBytes
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetRxBytes() uint64 {
+	if x != nil {
+		return x.RxBytes
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetReadBytes() uint64 {
+	if x != nil {
+		return x.ReadBytes
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetWriteBytes() uint64 {
+	if x != nil {
+		return x.WriteBytes
+	}
+	return 0
+}
+
+func (x *NestedAppMetrics) GetChildContainerMetrics() []*NestedAppMetrics {
+	if x != nil {
+		return x.ChildContainerMetrics
+	}
+	return nil
+}
+
+var File_nestedappinstancemetrics_nestedappinstancemetrics_proto protoreflect.FileDescriptor
+
+var file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDesc = []byte{
+	0x0a, 0x37, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61,
+	0x6e, 0x63, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6e, 0x65, 0x73, 0x74, 0x65,
+	0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x6f, 0x72, 0x67, 0x2e, 0x6c,
+	0x66, 0x65, 0x64, 0x67, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2e,
+	0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xc9,
+	0x03, 0x0a, 0x10, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x50,
+	0x69, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x69, 0x64, 0x73, 0x12,
+	0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
+	0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x50, 0x55, 0x54, 0x6f,
+	0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x43, 0x50, 0x55, 0x54, 0x6f,
+	0x74, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x50, 0x55,
+	0x54, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x53, 0x79, 0x73,
+	0x74, 0x65, 0x6d, 0x43, 0x50, 0x55, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x55,
+	0x73, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x55, 0x73,
+	0x65, 0x64, 0x4d, 0x65, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
+	0x65, 0x64, 0x4d, 0x65, 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x41, 0x6c, 0x6c,
+	0x6f, 0x63, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x54, 0x78, 0x42,
+	0x79, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x54, 0x78, 0x42, 0x79,
+	0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0a,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x52, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x0a,
+	0x09, 0x52, 0x65, 0x61, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x09, 0x52, 0x65, 0x61, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x57,
+	0x72, 0x69, 0x74, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x0a, 0x57, 0x72, 0x69, 0x74, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x17, 0x63,
+	0x68, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6f,
+	0x72, 0x67, 0x2e, 0x6c, 0x66, 0x65, 0x64, 0x67, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x2e, 0x74, 0x6f,
+	0x6f, 0x6c, 0x73, 0x2e, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x4d, 0x65, 0x74, 0x72,
+	0x69, 0x63, 0x73, 0x52, 0x15, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+	0x6e, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x49, 0x5a, 0x47, 0x67, 0x69,
+	0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x66, 0x2d, 0x65, 0x64, 0x67, 0x65,
+	0x2f, 0x65, 0x76, 0x65, 0x2d, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69,
+	0x6d, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x6e, 0x65, 0x73,
+	0x74, 0x65, 0x64, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescOnce sync.Once
+	file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescData = file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDesc
+)
+
+func file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescGZIP() []byte {
+	file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescOnce.Do(func() {
+		file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescData)
+	})
+	return file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDescData
+}
+
+var file_nestedappinstancemetrics_nestedappinstancemetrics_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_nestedappinstancemetrics_nestedappinstancemetrics_proto_goTypes = []interface{}{
+	(*NestedAppMetrics)(nil), // 0: org.lfedge.eve.tools.runtimemetrics.NestedAppMetrics
+}
+var file_nestedappinstancemetrics_nestedappinstancemetrics_proto_depIdxs = []int32{
+	0, // 0: org.lfedge.eve.tools.runtimemetrics.NestedAppMetrics.child_container_metrics:type_name -> org.lfedge.eve.tools.runtimemetrics.NestedAppMetrics
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_nestedappinstancemetrics_nestedappinstancemetrics_proto_init() }
+func file_nestedappinstancemetrics_nestedappinstancemetrics_proto_init() {
+	if File_nestedappinstancemetrics_nestedappinstancemetrics_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_nestedappinstancemetrics_nestedappinstancemetrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*NestedAppMetrics); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_nestedappinstancemetrics_nestedappinstancemetrics_proto_goTypes,
+		DependencyIndexes: file_nestedappinstancemetrics_nestedappinstancemetrics_proto_depIdxs,
+		MessageInfos:      file_nestedappinstancemetrics_nestedappinstancemetrics_proto_msgTypes,
+	}.Build()
+	File_nestedappinstancemetrics_nestedappinstancemetrics_proto = out.File
+	file_nestedappinstancemetrics_nestedappinstancemetrics_proto_rawDesc = nil
+	file_nestedappinstancemetrics_nestedappinstancemetrics_proto_goTypes = nil
+	file_nestedappinstancemetrics_nestedappinstancemetrics_proto_depIdxs = nil
+}
diff --git a/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstanceinventory.proto b/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstanceinventory.proto
new file mode 100644
index 0000000..1184c4d
--- /dev/null
+++ b/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstanceinventory.proto
@@ -0,0 +1,32 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppStatus is a DomainStatus structure
+// for the Nested App.
+// intended for EVE logging infrastructure to
+// consume and separate runtime log entries for each
+// app instance running inside a runtime and logging
+// to the console.
+message NestedAppStatus {
+  // App Id of the nested app inside the runtime
+  string app_id = 1;
+
+  // App Name is the app instance display name
+  string app_name = 2;
+
+  // Logging has been disabled in the runtime
+  // for this nested app instance inside the runtime
+  bool disable_logs = 3;
+}
+
+// Inventory object returned via an http server
+// running inside a nested app instance runtime on eve.
+message NestedAppInventory {
+  // UUIDs of the nested/virtual AppInstances as provided to the agent
+  // in the Patch Envelope Config
+  repeated NestedAppStatus apps = 1;
+}
diff --git a/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto b/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
new file mode 100644
index 0000000..ee675a3
--- /dev/null
+++ b/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
@@ -0,0 +1,22 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+message NestedAppInstanceLogMsg {
+  // AppId of the nested app instance / virtual app instance
+  // eg. docker compose app instance ID
+  string nested_app_id = 1;
+
+  // container_name is the shortened name of the container.
+  // eg. compose app container name is project_name-service-replica
+  // this field should contain the service-replica suffix.
+  string container_name = 2;
+
+  // msg is the original log from the runtime container
+  string msg = 3;
+}
diff --git a/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto b/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
new file mode 100644
index 0000000..a89d679
--- /dev/null
+++ b/runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
@@ -0,0 +1,44 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppMetrics object to serve as a metric
+// for a top level appinstance and all containers
+// inside an app instance.  A single parent NestedAppMetrics returned from
+// GET /api/v1/metrics/nested-app-id/<app-id>
+message NestedAppMetrics {
+  // The parent NestedAppMetrics.Id will have an app instance uuid
+  // to show app level metrics where the app is a group of one or more containers.
+  // The child_container_metrics NestedAppMetrics.Id will have a container id
+  // where the prefix matches the parent id.
+  string id = 1;
+
+  string status = 2;  // uptime, pause, stop status
+  uint32 Pids = 3;    // number of PIDs within the container
+
+  // CPU stats
+  int64 uptime = 4;         // unix.nano, time since container starts
+  uint64 CPUTotal = 5;      // container CPU since starts in nanosec
+  uint64 SystemCPUTotal = 6;// total system, user, idle in nanosec
+
+  // Memory stats
+  uint32 UsedMem = 7;      // in MBytes
+  uint32 AllocatedMem = 8; // in MBytes
+
+  // Network stats
+  uint64 TxBytes = 9;  // in Bytes
+  uint64 RxBytes = 10; // in Bytes
+
+  // Disk stats
+  uint64 ReadBytes = 11;  // in MBytes
+  uint64 WriteBytes = 12; // in MBytes
+
+  // Child container metrics
+  // id field should be a container name where the prefix 
+  // is the app instance id / above parent id.  
+  // For a compose app these id fields will be '<appid>-<service>-<replica>'
+  repeated NestedAppMetrics child_container_metrics = 13;
+}


Reviews:
user: login: naiming-zededa
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-06T22:02:52Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T23:40:27Z
user: login: naiming-zededa
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-07T04:19:55Z
user: login: naiming-zededa
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-07T20:00:17Z
user: login: naiming-zededa
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-10T00:31:10Z
user: login: naiming-zededa
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-10T02:21:50Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T19:02:40Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T20:22:17Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T20:49:37Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T21:17:19Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T21:44:40Z
user: login: naiming-zededa
body: LGTM
state: APPROVED
author_association: NONE
submitted_at: 2025-03-10T23:15:12Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T10:02:48Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T22:32:20Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T03:03:11Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T09:31:02Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T09:33:15Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T15:05:17Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T15:19:19Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T22:27:29Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T22:30:01Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T22:31:04Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T16:21:28Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T16:31:16Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T21:46:24Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T21:47:49Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T21:48:48Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T21:51:24Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T17:08:33Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T17:11:42Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T17:12:40Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T17:13:05Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T18:38:45Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T20:12:17Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T18:41:53Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T18:44:12Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T19:21:32Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T20:16:47Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T23:38:43Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T23:56:35Z
user: login: eriknordmark
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T08:21:55Z
user: login: andrewd-zededa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-20T21:16:25Z

Review comments:
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: naiming-zededa
body: We may want to define a TCP port number, which is used for metrics stats collection endpoint for this.
created_at: 2025-03-06T22:02:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: @naiming-zededa Can we have that controller defined in cloud-init?
created_at: 2025-03-06T23:40:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: naiming-zededa
body: @andrewd-zededa for the collectstatsIP we have controller to decide since it has the knowledge based on the network-instance subnet info. But this tcp port number should be fixed one, static, should never change, if we have controller to do it, we need to extend EVE API in AppInstanceConfig to pass down this value, so it does not seem to be a good idea.
created_at: 2025-03-07T04:19:55Z
author_association: NONE
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
+// Redefined AppContainerStats object from pillar
+// as a proto object for the zcompose-proto repo
+// this will serve as a combined metric for all containers
+// under a compose app
+message AppContainerStats {
+   // container_name will be the app-id of the
+   // compose app Not a child container in the compose app
+   string container_name = 1; // unique under an App
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: naiming-zededa
body: Hi @andrewd-zededa , can we have two items here, one is 'string container_uuid', and other is 'container_name', for the nested-app. I need to publish this nested-app 'domain-status', and it will be good to have a name.
created_at: 2025-03-07T20:00:17Z
author_association: NONE
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
+// Redefined AppContainerStats object from pillar
+// as a proto object for the zcompose-proto repo
+// this will serve as a combined metric for all containers
+// under a compose app
+message AppContainerStats {
+   // container_name will be the app-id of the
+   // compose app Not a child container in the compose app
+   string container_name = 1; // unique under an App
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: naiming-zededa
body: or rather put this app-name in the `message NestedAppStatus` side, w/ app_id, app_name, and here the AppContainerStats only has the uuid.
created_at: 2025-03-10T00:31:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: naiming-zededa
body: @andrewd-zededa we also need to define the URL path here, something like
api/v1/nested-app-status
api/v1/nested-app-stats

created_at: 2025-03-10T02:21:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: README.md has /api/v1 defined as a path prefix for endpoints.  As discussed I'll make the adjustments to the metrics endpoint to append the object and id eg. /api/v1/metrics/nested-app-id/\<app-id\>
created_at: 2025-03-10T19:02:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,35 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for a webserver running inside of a 'runtime'
+on eve which returns metric data for containers or groups of containers which
+reside in the runtime.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime metric server.
+All endpoints will start with an api prefix path "/api/v1/" until further versions are defined.
+All endpoints are accessible at tcp port 57475.
path: runtimemetrics/README.md
user: login: eriknordmark
body: I assume this is using http and not https.
It makes sense to say something about security - basically that this TCP port is only available from EVE-OS itself. Is that correct?
created_at: 2025-03-10T20:22:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,35 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for a webserver running inside of a 'runtime'
+on eve which returns metric data for containers or groups of containers which
+reside in the runtime.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime metric server.
+All endpoints will start with an api prefix path "/api/v1/" until further versions are defined.
+All endpoints are accessible at tcp port 57475.
path: runtimemetrics/README.md
user: login: andrewd-zededa
body: @eriknordmark yes http and only internal.  I'll note this in the readme
created_at: 2025-03-10T20:49:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: port number noted in README.md
created_at: 2025-03-10T21:17:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+message ComposeMetricsRoot {
+	// This will import and use the eve pillar type
+	// Each app metric here wil be the combined metric data for all 
+	// services/containers in a compose app.
+	repeated AppContainerStats app_metric = 1;
+}
+
+// Redefined AppContainerStats object from pillar
+// as a proto object for the zcompose-proto repo
+// this will serve as a combined metric for all containers
+// under a compose app
+message AppContainerStats {
+   // container_name will be the app-id of the
+   // compose app Not a child container in the compose app
+   string container_name = 1; // unique under an App
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: Ok, I think the latest push should resolve this metrics issue.  Please take a look @naiming-zededa 
created_at: 2025-03-10T21:44:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
+the CollectStatsIPAddr as defined in app instance config.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime
+metric server. All endpoints will start with an api prefix path "/api/v1/"
+until further versions are defined. All endpoints are accessible over
+http at tcp port 57475.
path: runtimemetrics/README.md
user: login: eriknordmark
body: Can you please add something about the intended approach to security here?

If the intent is to block external access to this port then please state that.
created_at: 2025-03-11T10:02:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
+the CollectStatsIPAddr as defined in app instance config.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime
+metric server. All endpoints will start with an api prefix path "/api/v1/"
+until further versions are defined. All endpoints are accessible over
+http at tcp port 57475.
path: runtimemetrics/README.md
user: login: andrewd-zededa
body: Yes I'll update the readme with that
created_at: 2025-03-12T22:32:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
+the CollectStatsIPAddr as defined in app instance config.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime
+metric server. All endpoints will start with an api prefix path "/api/v1/"
+until further versions are defined. All endpoints are accessible over
+http at tcp port 57475.
path: runtimemetrics/README.md
user: login: andrewd-zededa
body: @eriknordmark do the lines above this in 7-10 cover your concern?
created_at: 2025-03-13T03:03:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
path: runtimemetrics/README.md
user: login: eriknordmark
body: Please upper-case EVE-OS, EVE, etc. Presumably VM is also upper case.

I don't know what "available to EVE-OS" means. 
See next comment.
created_at: 2025-03-13T09:31:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
+the CollectStatsIPAddr as defined in app instance config, this interface
+will be on an airgapped local network with no external access outside of
path: runtimemetrics/README.md
user: login: eriknordmark
body: Is it going to be a unique and separate network instance for this?
I'm asking because we don't view e.g., the default network instance as being air-gapped. It is connected to the outside via a NAT.

To me the key property is that TCP port 57475is (aka must be) blocked from any external access by EVE-OS so that it can only be used for communication between EVE-OS and the VM.
created_at: 2025-03-13T09:33:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
+the CollectStatsIPAddr as defined in app instance config, this interface
+will be on an airgapped local network with no external access outside of
path: runtimemetrics/README.md
user: login: andrewd-zededa
body: Yes the network instance for this must be a not default network instance, a separate one with no ports attached to it.  
created_at: 2025-03-13T15:05:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
path: runtimemetrics/README.md
user: login: andrewd-zededa
body: Yes I'll fix those
created_at: 2025-03-13T15:19:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on eve which returns metric data to eve for containers or groups
+of containers which reside in the runtime.  This runtime can be a vm and
+is expected to be running inside an eve AppInstance.  
+The server listens on an address only available to eve-os,
+the CollectStatsIPAddr as defined in app instance config, this interface
+will be on an airgapped local network with no external access outside of
path: runtimemetrics/README.md
user: login: eriknordmark
body: Ok
created_at: 2025-03-13T22:27:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// AppContainerStats object to serve as a metric
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: eriknordmark
body: Should we generalize this by naming it AppNestedStats instead of AppContainerStats?
That way if we want to use it where the thing inside an app instance is one or more helm charts or kubernetes pods the name still makes sense.
created_at: 2025-03-13T22:30:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+proto-container-build:
+	docker build -f Dockerfile -t runtimemetrics-builder .
+
+gen-go:
+	docker run --rm --env HOME=/src -v $(PWD):/src -w /src -u $$(id -u) runtimemetrics-builder make proto
+
+.PHONY: proto-api-% proto proto-container-build gen-go
+
+# Target run in runtimemetrics-builder 'proto-container-build'
+proto: go
+	@echo Done building protobuf, you may want to vendor it into your projects, e.g. lf-edge/eve.
+	@echo See ./go/README.md for more information.
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+go: PROTOC_OUT_OPTS=paths=source_relative:
+go: proto-api-go
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+proto-api-%:
+	rm -rf $*/*/; mkdir -p $* # building $@
+	protoc -I./proto --$(*)_out=$(PROTOC_OUT_OPTS)./$* proto/*/*.proto
+
+help:
+	@echo "runtimemetrics contains proto objects to generate structures for the webserver running inside an"
+	@echo "	eve runtime vm which reports nested app instance container metrics"
path: runtimemetrics/Makefile
user: login: eriknordmark
body: Note that if we want to replace container with nested it makes sense to look for all instances of "container" in this PR.
created_at: 2025-03-13T22:31:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// AppContainerStats object to serve as a metric
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: Yeah we can rename this, AppNestedStats sounds fine or NestedAppContainerGroupMetric but that's kind of long.  I'll push up a rename for your suggestion.
created_at: 2025-03-14T16:21:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+proto-container-build:
+	docker build -f Dockerfile -t runtimemetrics-builder .
+
+gen-go:
+	docker run --rm --env HOME=/src -v $(PWD):/src -w /src -u $$(id -u) runtimemetrics-builder make proto
+
+.PHONY: proto-api-% proto proto-container-build gen-go
+
+# Target run in runtimemetrics-builder 'proto-container-build'
+proto: go
+	@echo Done building protobuf, you may want to vendor it into your projects, e.g. lf-edge/eve.
+	@echo See ./go/README.md for more information.
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+go: PROTOC_OUT_OPTS=paths=source_relative:
+go: proto-api-go
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+proto-api-%:
+	rm -rf $*/*/; mkdir -p $* # building $@
+	protoc -I./proto --$(*)_out=$(PROTOC_OUT_OPTS)./$* proto/*/*.proto
+
+help:
+	@echo "runtimemetrics contains proto objects to generate structures for the webserver running inside an"
+	@echo "	eve runtime vm which reports nested app instance container metrics"
path: runtimemetrics/Makefile
user: login: andrewd-zededa
body: The terminology we converge on here has a lot of options.  In general for groups of containers there are pods (k8s) and stacks (compose) which could be used for the app container terminology.  The nesting/nested usage so far has been towards the location of a runtime or the source of the metrics.  I'm curious if we may want to keep the 'nested' terminology to the interface in url paths and then something more specific to the app itself in the structure name.

eg.
url path currently /api/v1/metrics/nested-app-id/<app-id>
then metric structure:
AppStackMetric?

created_at: 2025-03-14T16:31:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppStatus is a DomainStatus structure
+// for the Nested App.
+// intended for EVE logging infrastructure to
+// consume and separate runtime log entries for each
+// app instance running inside a runtime and logging
+// to the console.
+message NestedAppStatus {
+  // App Id of the nested app inside the runtime
+  string app_id = 1;
+
+  // App Name is the app instance display name
+  string app_name = 2;
+
+  // Logging has been disabled in the runtime
+  // for this nested app instance inside the runtime
+  bool disable_logs = 3;
+}
+
+// Inventory object returned via an http server
+// running inside a container runtime app instance on eve.
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstanceinventory.proto
user: login: eriknordmark
body: Could be a helm runtime so I'd replace "container" with "nested" here.
created_at: 2025-03-17T21:46:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,22 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+message NestedAppInstanceLogMsg {
+  // AppId of the nested app instance / virtual app instance
+  // eg. docker compose app instance ID
+  string nested_app_id = 1;
+
+  // container_name is the shortened name of the container.
+  // eg. compose app container name is project_name-service-replica
+  // this field should contain the service-replica suffix.
+  string container_name = 2;
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
user: login: eriknordmark
body: Should this be nested_app_name to generalize?
created_at: 2025-03-17T21:47:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// AppContainerStats object to serve as a metric
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: eriknordmark
body: For the others like status to have "Nested" as the first part of the name so NestedAppMetrics might make sense.
created_at: 2025-03-17T21:48:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+proto-container-build:
+	docker build -f Dockerfile -t runtimemetrics-builder .
+
+gen-go:
+	docker run --rm --env HOME=/src -v $(PWD):/src -w /src -u $$(id -u) runtimemetrics-builder make proto
+
+.PHONY: proto-api-% proto proto-container-build gen-go
+
+# Target run in runtimemetrics-builder 'proto-container-build'
+proto: go
+	@echo Done building protobuf, you may want to vendor it into your projects, e.g. lf-edge/eve.
+	@echo See ./go/README.md for more information.
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+go: PROTOC_OUT_OPTS=paths=source_relative:
+go: proto-api-go
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+proto-api-%:
+	rm -rf $*/*/; mkdir -p $* # building $@
+	protoc -I./proto --$(*)_out=$(PROTOC_OUT_OPTS)./$* proto/*/*.proto
+
+help:
+	@echo "runtimemetrics contains proto objects to generate structures for the webserver running inside an"
+	@echo "	eve runtime vm which reports nested app instance container metrics"
path: runtimemetrics/Makefile
user: login: eriknordmark
body: For this particular line you can just drop "container" since you already have "nested".

What are all of the URLs? /api/v1/status/netstat-app-id/ and then the /api/v1/metrics/nested-app-id/?

Can't we call the Nested struct NestedAppMetrics?
created_at: 2025-03-17T21:51:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,22 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+message NestedAppInstanceLogMsg {
+  // AppId of the nested app instance / virtual app instance
+  // eg. docker compose app instance ID
+  string nested_app_id = 1;
+
+  // container_name is the shortened name of the container.
+  // eg. compose app container name is project_name-service-replica
+  // this field should contain the service-replica suffix.
+  string container_name = 2;
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
user: login: andrewd-zededa
body: I think the container name here was intended to allow filtering each child container inside the nested app instance container group.  @naiming-zededa do you want an additional field for the nested_app_name here as well?
created_at: 2025-03-18T17:08:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+proto-container-build:
+	docker build -f Dockerfile -t runtimemetrics-builder .
+
+gen-go:
+	docker run --rm --env HOME=/src -v $(PWD):/src -w /src -u $$(id -u) runtimemetrics-builder make proto
+
+.PHONY: proto-api-% proto proto-container-build gen-go
+
+# Target run in runtimemetrics-builder 'proto-container-build'
+proto: go
+	@echo Done building protobuf, you may want to vendor it into your projects, e.g. lf-edge/eve.
+	@echo See ./go/README.md for more information.
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+go: PROTOC_OUT_OPTS=paths=source_relative:
+go: proto-api-go
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+proto-api-%:
+	rm -rf $*/*/; mkdir -p $* # building $@
+	protoc -I./proto --$(*)_out=$(PROTOC_OUT_OPTS)./$* proto/*/*.proto
+
+help:
+	@echo "runtimemetrics contains proto objects to generate structures for the webserver running inside an"
+	@echo "	eve runtime vm which reports nested app instance container metrics"
path: runtimemetrics/Makefile
user: login: andrewd-zededa
body: url endpoints are:
- GET /api/v1/inventory/nested-app-id
- GET /api/v1/metrics/nested-app-id/<app-id>
created_at: 2025-03-18T17:11:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppStatus is a DomainStatus structure
+// for the Nested App.
+// intended for EVE logging infrastructure to
+// consume and separate runtime log entries for each
+// app instance running inside a runtime and logging
+// to the console.
+message NestedAppStatus {
+  // App Id of the nested app inside the runtime
+  string app_id = 1;
+
+  // App Name is the app instance display name
+  string app_name = 2;
+
+  // Logging has been disabled in the runtime
+  // for this nested app instance inside the runtime
+  bool disable_logs = 3;
+}
+
+// Inventory object returned via an http server
+// running inside a container runtime app instance on eve.
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstanceinventory.proto
user: login: andrewd-zededa
body: fixed
created_at: 2025-03-18T17:12:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// AppContainerStats object to serve as a metric
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: Fixed to NestedAppMetrics
created_at: 2025-03-18T17:13:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,22 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+message NestedAppInstanceLogMsg {
+  // AppId of the nested app instance / virtual app instance
+  // eg. docker compose app instance ID
+  string nested_app_id = 1;
+
+  // container_name is the shortened name of the container.
+  // eg. compose app container name is project_name-service-replica
+  // this field should contain the service-replica suffix.
+  string container_name = 2;
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
user: login: eriknordmark
body: In the case of Compose those are the same, right?
Or are you really reaching one level deeper by reporting for the container inside the compose file (which is in turn inside the runtime VM aka app instance)?
If so this should be called nested^2 app_name or something.
created_at: 2025-03-18T18:38:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,22 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+message NestedAppInstanceLogMsg {
+  // AppId of the nested app instance / virtual app instance
+  // eg. docker compose app instance ID
+  string nested_app_id = 1;
+
+  // container_name is the shortened name of the container.
+  // eg. compose app container name is project_name-service-replica
+  // this field should contain the service-replica suffix.
+  string container_name = 2;
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
user: login: andrewd-zededa
body: No for example if a dir with name 'myapp' has a compose application defined inside with services 'frontend' and 'backend' each of one replica then the deployed app will have two containers 'myapp-frontend-1' and 'myapp-backend-1' and docker engine can be easily configured to tag these logs separately.  
created_at: 2025-03-18T20:12:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,22 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// This object will be embedded in the content field
+// of the existing app instance log entry.
+message NestedAppInstanceLogMsg {
+  // AppId of the nested app instance / virtual app instance
+  // eg. docker compose app instance ID
+  string nested_app_id = 1;
+
+  // container_name is the shortened name of the container.
+  // eg. compose app container name is project_name-service-replica
+  // this field should contain the service-replica suffix.
+  string container_name = 2;
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancelog.proto
user: login: andrewd-zededa
body: @eriknordmark I talked with @naiming-zededa and we will not add a nested_app_name here to keep the log entry payloads smaller for uploads to the controller.  The controller has the app instance name to match from the NestedAppInstanceLogMsg.nested_app_id.
created_at: 2025-03-19T18:41:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+proto-container-build:
+	docker build -f Dockerfile -t runtimemetrics-builder .
+
+gen-go:
+	docker run --rm --env HOME=/src -v $(PWD):/src -w /src -u $$(id -u) runtimemetrics-builder make proto
+
+.PHONY: proto-api-% proto proto-container-build gen-go
+
+# Target run in runtimemetrics-builder 'proto-container-build'
+proto: go
+	@echo Done building protobuf, you may want to vendor it into your projects, e.g. lf-edge/eve.
+	@echo See ./go/README.md for more information.
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+go: PROTOC_OUT_OPTS=paths=source_relative:
+go: proto-api-go
+
+# Target run in the runtimemetrics-builder 'proto-container-build'
+proto-api-%:
+	rm -rf $*/*/; mkdir -p $* # building $@
+	protoc -I./proto --$(*)_out=$(PROTOC_OUT_OPTS)./$* proto/*/*.proto
+
+help:
+	@echo "runtimemetrics contains proto objects to generate structures for the webserver running inside an"
+	@echo "	eve runtime vm which reports nested app instance container metrics"
path: runtimemetrics/Makefile
user: login: andrewd-zededa
body: NestedAppMetric rename in latest push, resolving this.
created_at: 2025-03-19T18:44:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on EVE which returns metric data to EVE for containers or groups
+of containers which reside in the runtime.  This runtime can be a VM and
+is expected to be running inside an EVE AppInstance.
+The server listens on the address defined by CollectStatsIPAddr in app
+instance config, this address will be on an airgapped local network
+instance with no external access outside of EVE.  The consumer of this
+data is in the pillar service container in EVE-OS.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime
+metric server. All endpoints will start with an api prefix path "/api/v1/"
+until further versions are defined. All endpoints are accessible over
+http at tcp port 57475.
+
+### Inventory
+
+GET /api/v1/inventory/nested-app-id
+
+Return codes:
+
+* Inventory Returned: `200`
+* Non-GET type request: `405`
+
+Response:
+
+The body will contain the NestedAppInventory structure in json form.
+
+### Metrics
+
+GET /api/v1/metrics/nested-app-id/<app-id>
+
+Return codes:
+
+* Metrics returned: `200`
+* App Id not in uuid format: `400`
+* App Id not defined in runtime: `404`
+* Non-GET type request: `405`
+
+Response:
+
+The body will contain the AppContainerStats structure in json form.
path: runtimemetrics/README.md
user: login: eriknordmark
body: Shouldn't this comment be updated?
created_at: 2025-03-19T19:21:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppMetrics object to serve as a metric
+// for a top level appinstance and all containers
+// inside an app instance.  Returned from
+// GET /api/v1/metrics/nested-app-id/<app-id>
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: eriknordmark
body: So the GET is to /api/v1/metrics/nested-app-id/<app-id> but  can there be several container ids name "<appid>-<service>-<replica>"?
If so will all of them be returned for a single GET of the <app-id>?
Will those appear in the child_container_metrics field?

Does that mean that on line 16 below, the top-level one will have an id of just "<appid>"? Or something else??
created_at: 2025-03-19T20:16:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,45 @@
+# runtimemetrics
+
+runtimemetrics defines an interface for an http webserver running inside of a
+'runtime' on EVE which returns metric data to EVE for containers or groups
+of containers which reside in the runtime.  This runtime can be a VM and
+is expected to be running inside an EVE AppInstance.
+The server listens on the address defined by CollectStatsIPAddr in app
+instance config, this address will be on an airgapped local network
+instance with no external access outside of EVE.  The consumer of this
+data is in the pillar service container in EVE-OS.
+
+## Endpoints
+
+The following are the API endpoints which must be implemented by the runtime
+metric server. All endpoints will start with an api prefix path "/api/v1/"
+until further versions are defined. All endpoints are accessible over
+http at tcp port 57475.
+
+### Inventory
+
+GET /api/v1/inventory/nested-app-id
+
+Return codes:
+
+* Inventory Returned: `200`
+* Non-GET type request: `405`
+
+Response:
+
+The body will contain the NestedAppInventory structure in json form.
+
+### Metrics
+
+GET /api/v1/metrics/nested-app-id/<app-id>
+
+Return codes:
+
+* Metrics returned: `200`
+* App Id not in uuid format: `400`
+* App Id not defined in runtime: `404`
+* Non-GET type request: `405`
+
+Response:
+
+The body will contain the AppContainerStats structure in json form.
path: runtimemetrics/README.md
user: login: andrewd-zededa
body: yes I'll fix it
created_at: 2025-03-19T23:38:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppMetrics object to serve as a metric
+// for a top level appinstance and all containers
+// inside an app instance.  Returned from
+// GET /api/v1/metrics/nested-app-id/<app-id>
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: The metrics GET will only return a parent NestedAppMetrics structure associated with the uuid in the url path.  The parent will contain one or more under child_container_metrics.  The id on the parent will be app instance uuid of the compose app for example and the child_container_metrics entries will have id set to the container names included in the compose app such as "uuid-db-1", "uuid-frontend-1".
created_at: 2025-03-19T23:56:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppMetrics object to serve as a metric
+// for a top level appinstance and all containers
+// inside an app instance.  Returned from
+// GET /api/v1/metrics/nested-app-id/<app-id>
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: eriknordmark
body: OK, that wasn't immediately obvious do to the comment on line 15 about the container id.
It would be helpful to have line 14 say what the id is for the parent.
created_at: 2025-03-20T08:21:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+// Copyright(c) 2025 Zededa, Inc.
+
+syntax = "proto3";
+
+package org.lfedge.eve.tools.runtimemetrics;
+option go_package  = "github.com/lf-edge/eve-tools/runtimemetrics/go/nestedappinstancemetrics";
+
+// NestedAppMetrics object to serve as a metric
+// for a top level appinstance and all containers
+// inside an app instance.  Returned from
+// GET /api/v1/metrics/nested-app-id/<app-id>
path: runtimemetrics/proto/nestedappinstancemetrics/nestedappinstancemetrics.proto
user: login: andrewd-zededa
body: Updated comments for Id fields in NestedAppMetric to more clearly declare usage for parent and child NestedAppMetric.
created_at: 2025-03-20T21:16:25Z
author_association: CONTRIBUTOR

PR comments:
user: login: andrewd-zededa
created_at: 2025-03-07T00:13:09Z
body: @naiming-zededa pushed up with latest log format, and feedback from design doc on inventory object name.  Included a basic readme on the http server endpoints.
author_association: CONTRIBUTOR
user: login: andrewd-zededa
created_at: 2025-03-13T21:24:54Z
body: @eriknordmark I pushed more changes to the top paragraph in README.md to hopefully clarify the networking and security explanation.  Please let me know if this resolves your concerns.
author_association: CONTRIBUTOR
user: login: eriknordmark
created_at: 2025-03-17T21:53:04Z
body: Note that if you think it is useful we can add an enum for "NestedAppType" which could have values for container, compose, helm, etc. But presumably the controller would already know this from what it deployed.
author_association: CONTRIBUTOR
user: login: andrewd-zededa
created_at: 2025-03-20T21:17:02Z
body: @eriknordmark updated proto comments, please review as time allows.
author_association: CONTRIBUTOR