You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2022/07/14 14:26:58 UTC

[skywalking-cli] branch master updated: Add commands for support network profiling (#158)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-cli.git


The following commit(s) were added to refs/heads/master by this push:
     new a73f653  Add commands for support network profiling (#158)
a73f653 is described below

commit a73f65367b335e08412c0471e85ad8f15e92d411
Author: mrproliu <74...@qq.com>
AuthorDate: Thu Jul 14 22:26:55 2022 +0800

    Add commands for support network profiling (#158)
---
 CHANGES.md                                         |  3 +
 assets/graphqls/dependency/ProcessTopology.graphql | 36 +++++++++
 .../ebpf/CreateEBPFNetworkProfilingTask.graphql    | 24 ++++++
 .../ebpf/KeepNetworkProfilingTask.graphql          | 23 ++++++
 go.mod                                             |  2 +-
 go.sum                                             |  4 +-
 internal/commands/dependency/dependency.go         |  1 +
 .../thermodynamic.go => dependency/process.go}     | 49 ++++--------
 internal/commands/interceptor/entity.go            | 12 +++
 internal/commands/interceptor/process.go           | 91 ++++++++++++++++++++++
 internal/commands/metrics/linear/linear-metrics.go |  2 +
 .../metrics/linear/multiple-linear-metrics.go      |  2 +
 internal/commands/metrics/single/single-metrics.go |  2 +
 .../metrics/thermodynamic/thermodynamic.go         |  2 +
 internal/commands/profiling/ebpf/create/create.go  |  1 +
 .../ebpf/create/network.go}                        | 61 +++++----------
 internal/commands/profiling/ebpf/ebpf.go           |  2 +
 .../ebpf/{create/create.go => keep/keep.go}        | 11 ++-
 internal/commands/profiling/ebpf/keep/network.go   | 57 ++++++++++++++
 .../ebpf/create/create.go => flags/process.go}     | 31 ++++++--
 pkg/graphql/dependency/dependency.go               | 12 +++
 pkg/graphql/profiling/ebpf.go                      | 22 ++++++
 pkg/graphql/utils/parser.go                        |  4 +-
 pkg/graphql/utils/parser_test.go                   | 31 +++++++-
 24 files changed, 391 insertions(+), 94 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index ca7a107..31b9d69 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,9 @@ Release Notes.
 - [Breaking Change] Remove `total` field in `trace list` and `logs list` commands.(#152)
 - [Breaking Change] Remove `total` field in `event list`, `browser logs list`, `alarm list` commands.(#153)
 - Add `aggregate` flag in `profiling ebpf analysis` commands.(#154)
+- Add the sub-command `profiling ebpf create network` and `profiling ebpf keep network` to create and keep the network eBPF profiling task.(#158)
+- Add the sub-command `dependency process` to query the process relation.(#158)
+- Support query the metrics of process relation.(#158)
 
 0.10.0
 ------------------
diff --git a/assets/graphqls/dependency/ProcessTopology.graphql b/assets/graphqls/dependency/ProcessTopology.graphql
new file mode 100644
index 0000000..ec2dd0d
--- /dev/null
+++ b/assets/graphqls/dependency/ProcessTopology.graphql
@@ -0,0 +1,36 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query ($serviceInstanceId: ID!, $duration: Duration!){
+    result: getProcessTopology(serviceInstanceId: $serviceInstanceId, duration: $duration) {
+        nodes {
+            id
+            serviceId
+            serviceName
+            serviceInstanceId
+            serviceInstanceName
+            name
+            isReal
+        }
+        calls {
+            source
+            target
+            id
+            detectPoints
+        }
+    }
+}
\ No newline at end of file
diff --git a/assets/graphqls/profiling/ebpf/CreateEBPFNetworkProfilingTask.graphql b/assets/graphqls/profiling/ebpf/CreateEBPFNetworkProfilingTask.graphql
new file mode 100644
index 0000000..e3b45a6
--- /dev/null
+++ b/assets/graphqls/profiling/ebpf/CreateEBPFNetworkProfilingTask.graphql
@@ -0,0 +1,24 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+mutation ($request: EBPFProfilingNetworkTaskRequest!){
+    result: createEBPFNetworkProfiling(request: $request) {
+        status
+        id
+        errorReason
+    }
+}
\ No newline at end of file
diff --git a/assets/graphqls/profiling/ebpf/KeepNetworkProfilingTask.graphql b/assets/graphqls/profiling/ebpf/KeepNetworkProfilingTask.graphql
new file mode 100644
index 0000000..83525bc
--- /dev/null
+++ b/assets/graphqls/profiling/ebpf/KeepNetworkProfilingTask.graphql
@@ -0,0 +1,23 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+mutation ($taskId: ID!){
+    result: keepEBPFNetworkProfiling(taskId: $taskId) {
+        status
+        errorReason
+    }
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 8efc146..89b1960 100644
--- a/go.mod
+++ b/go.mod
@@ -24,5 +24,5 @@ require (
 	gopkg.in/yaml.v2 v2.4.0
 	k8s.io/apimachinery v0.21.1
 	sigs.k8s.io/controller-runtime v0.7.0
-	skywalking.apache.org/repo/goapi v0.0.0-20220519102801-965f76fbe437
+	skywalking.apache.org/repo/goapi v0.0.0-20220714130828-0d56d1f4c592
 )
diff --git a/go.sum b/go.sum
index d554069..009af6f 100644
--- a/go.sum
+++ b/go.sum
@@ -950,5 +950,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-skywalking.apache.org/repo/goapi v0.0.0-20220519102801-965f76fbe437 h1:tWUESKwKU50ZEzQJsOQv50qPvPHj72MjIxFwgeoM7Hg=
-skywalking.apache.org/repo/goapi v0.0.0-20220519102801-965f76fbe437/go.mod h1:uWwwvhcwe2MD/nJCg0c1EE/eL6KzaBosLHDfMFoEJ30=
+skywalking.apache.org/repo/goapi v0.0.0-20220714130828-0d56d1f4c592 h1:3UbXoMUpGBoYLvuUCaKPzlHCM9Q+enaaOcQ19QbTDr8=
+skywalking.apache.org/repo/goapi v0.0.0-20220714130828-0d56d1f4c592/go.mod h1:uWwwvhcwe2MD/nJCg0c1EE/eL6KzaBosLHDfMFoEJ30=
diff --git a/internal/commands/dependency/dependency.go b/internal/commands/dependency/dependency.go
index 65e343c..4b373e1 100644
--- a/internal/commands/dependency/dependency.go
+++ b/internal/commands/dependency/dependency.go
@@ -29,5 +29,6 @@ var Command = &cli.Command{
 		EndpointCommand,
 		ServiceCommand,
 		InstanceCommand,
+		ProcessCommand,
 	},
 }
diff --git a/internal/commands/metrics/thermodynamic/thermodynamic.go b/internal/commands/dependency/process.go
similarity index 62%
copy from internal/commands/metrics/thermodynamic/thermodynamic.go
copy to internal/commands/dependency/process.go
index a34199b..8a89679 100644
--- a/internal/commands/metrics/thermodynamic/thermodynamic.go
+++ b/internal/commands/dependency/process.go
@@ -15,72 +15,53 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package thermodynamic
+package dependency
 
 import (
-	"github.com/urfave/cli/v2"
-
 	"github.com/apache/skywalking-cli/internal/commands/interceptor"
 	"github.com/apache/skywalking-cli/internal/flags"
 	"github.com/apache/skywalking-cli/internal/model"
 	"github.com/apache/skywalking-cli/pkg/display"
 	"github.com/apache/skywalking-cli/pkg/display/displayable"
-	"github.com/apache/skywalking-cli/pkg/graphql/metrics"
+	"github.com/apache/skywalking-cli/pkg/graphql/dependency"
+
+	"github.com/urfave/cli/v2"
 
 	api "skywalking.apache.org/repo/goapi/query"
 )
 
-var Command = &cli.Command{
-	Name:    "thermodynamic",
-	Aliases: []string{"td", "heatmap", "hp", "hm"},
-	Usage:   "query thermodynamic-type metrics defined in backend OAL",
-	UsageText: `Query the thermodynamic-type metrics defined in backend OAL.
-
-Examples:
-1. Query the global heatmap:
-$ swctl metrics thermodynamic --scope all --name all_heatmap
-`,
+var ProcessCommand = &cli.Command{
+	Name:    "process",
+	Aliases: []string{"pros"},
+	Usage:   "Query the process topology, based on the given service instance",
 	Flags: flags.Flags(
 		flags.DurationFlags,
-		flags.MetricsFlags,
+		flags.ServiceRelationFlags,
 		flags.InstanceRelationFlags,
-		flags.EndpointRelationFlags,
 	),
 	Before: interceptor.BeforeChain(
 		interceptor.DurationInterceptor,
-		interceptor.ParseEndpointRelation(false),
-		interceptor.ParseInstanceRelation(false),
+		interceptor.ParseInstance(true),
 	),
+
 	Action: func(ctx *cli.Context) error {
+		instanceID := ctx.String("instance-id")
+
 		end := ctx.String("end")
 		start := ctx.String("start")
 		step := ctx.Generic("step")
 
-		metricsName := ctx.String("name")
-		entity, err := interceptor.ParseEntity(ctx)
-		if err != nil {
-			return err
-		}
-
 		duration := api.Duration{
 			Start: start,
 			End:   end,
 			Step:  step.(*model.StepEnumValue).Selected,
 		}
 
-		metricsValues, err := metrics.Thermodynamic(ctx, api.MetricsCondition{
-			Name:   metricsName,
-			Entity: entity,
-		}, duration)
-
+		dependency, err := dependency.ProcessTopology(ctx, instanceID, duration)
 		if err != nil {
 			return err
 		}
 
-		return display.Display(ctx, &displayable.Displayable{
-			Data:     metricsValues,
-			Duration: duration,
-			Title:    metricsName,
-		})
+		return display.Display(ctx, &displayable.Displayable{Data: dependency})
 	},
 }
diff --git a/internal/commands/interceptor/entity.go b/internal/commands/interceptor/entity.go
index 8b110a6..d03f3e2 100644
--- a/internal/commands/interceptor/entity.go
+++ b/internal/commands/interceptor/entity.go
@@ -36,10 +36,12 @@ func ParseEntity(ctx *cli.Context) (*api.Entity, error) {
 	serviceID := ctx.String("service-id")
 	instance := ctx.String("instance-name")
 	endpoint := ctx.String("endpoint-name")
+	process := ctx.String("process-name")
 
 	destServiceID := ctx.String("dest-service-id")
 	destInstance := ctx.String("dest-instance-name")
 	destEndpoint := ctx.String("dest-endpoint-name")
+	destProcess := ctx.String("dest-process-name")
 
 	serviceName, isNormal, err := ParseServiceID(serviceID)
 	if err != nil {
@@ -56,13 +58,23 @@ func ParseEntity(ctx *cli.Context) (*api.Entity, error) {
 		Normal:                  &isNormal,
 		ServiceInstanceName:     &instance,
 		EndpointName:            &endpoint,
+		ProcessName:             &process,
 		DestServiceName:         &destServiceName,
 		DestNormal:              &destIsNormal,
 		DestServiceInstanceName: &destInstance,
 		DestEndpointName:        &destEndpoint,
+		DestProcessName:         &destProcess,
 	}
 	entity.Scope = utils.ParseScope(entity)
 
+	// adapt for the old version of backend
+	if *entity.ProcessName == "" {
+		entity.ProcessName = nil
+	}
+	if *entity.DestProcessName == "" {
+		entity.DestProcessName = nil
+	}
+
 	if logger.Log.GetLevel() <= logrus.DebugLevel {
 		s, _ := json.Marshal(&entity)
 		logger.Log.Debugf("entity: %+v", string(s))
diff --git a/internal/commands/interceptor/process.go b/internal/commands/interceptor/process.go
new file mode 100644
index 0000000..eaa5968
--- /dev/null
+++ b/internal/commands/interceptor/process.go
@@ -0,0 +1,91 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package interceptor
+
+import (
+	"crypto/sha256"
+	"fmt"
+
+	"github.com/urfave/cli/v2"
+)
+
+const (
+	processIDFlagName       = "process-id"
+	processNameFlagName     = "process-name"
+	destProcessNameFlagName = "dest-process-name"
+)
+
+// ParseProcess parses the process id or process name,
+// and converts the present one to the missing one.
+// See flags.InstanceFlags.
+func ParseProcess(required bool) func(*cli.Context) error {
+	return func(ctx *cli.Context) error {
+		if err := ParseService(required)(ctx); err != nil {
+			return err
+		}
+		if err := ParseInstance(required)(ctx); err != nil {
+			return err
+		}
+		return parseProcess(required, processIDFlagName, processNameFlagName, instanceIDFlagName)(ctx)
+	}
+}
+
+// ParseProcessRelation parses the source and destination service instance id or service instance name,
+// and converts the present one to the missing one respectively.
+// See flags.InstanceRelationFlags.
+func ParseProcessRelation(required bool) func(*cli.Context) error {
+	return func(ctx *cli.Context) error {
+		if err := ParseService(required)(ctx); err != nil {
+			return err
+		}
+		if err := ParseInstance(required)(ctx); err != nil {
+			return err
+		}
+		if err := ParseProcess(required)(ctx); err != nil {
+			return err
+		}
+		if ctx.String(destProcessNameFlagName) == "" && required {
+			return fmt.Errorf(`flag "--%s" must given`, destProcessNameFlagName)
+		}
+		return nil
+	}
+}
+
+func parseProcess(required bool, idFlagName, nameFlagName, instanceIDFlagName string) func(*cli.Context) error {
+	return func(ctx *cli.Context) error {
+		id := ctx.String(idFlagName)
+		name := ctx.String(nameFlagName)
+		instanceID := ctx.String(instanceIDFlagName)
+
+		if id == "" && name == "" {
+			if required {
+				return fmt.Errorf(`either flags "--%s" or "--%s" must be given`, idFlagName, nameFlagName)
+			}
+			return nil
+		}
+
+		if name != "" {
+			if instanceID == "" {
+				return fmt.Errorf(`"--%s" is specified but its related service name or id is not given`, nameFlagName)
+			}
+			id = fmt.Sprintf("%x", sha256.New().Sum([]byte(fmt.Sprintf("%s_%s", instanceID, name))))
+		}
+
+		return ctx.Set(idFlagName, id)
+	}
+}
diff --git a/internal/commands/metrics/linear/linear-metrics.go b/internal/commands/metrics/linear/linear-metrics.go
index 25930c4..d6c4d9a 100644
--- a/internal/commands/metrics/linear/linear-metrics.go
+++ b/internal/commands/metrics/linear/linear-metrics.go
@@ -52,11 +52,13 @@ $ swctl metrics linear --name=service_relation_client_cpm --service-name consume
 		flags.MetricsFlags,
 		flags.InstanceRelationFlags,
 		flags.EndpointRelationFlags,
+		flags.ProcessRelationFlags,
 	),
 	Before: interceptor.BeforeChain(
 		interceptor.DurationInterceptor,
 		interceptor.ParseEndpointRelation(false),
 		interceptor.ParseInstanceRelation(false),
+		interceptor.ParseProcessRelation(false),
 	),
 	Action: func(ctx *cli.Context) error {
 		end := ctx.String("end")
diff --git a/internal/commands/metrics/linear/multiple-linear-metrics.go b/internal/commands/metrics/linear/multiple-linear-metrics.go
index 5e987e0..3ffd1eb 100644
--- a/internal/commands/metrics/linear/multiple-linear-metrics.go
+++ b/internal/commands/metrics/linear/multiple-linear-metrics.go
@@ -51,6 +51,7 @@ $ swctl metrics multiple-linear --name all_percentile --labels=0,1,2,3,4 --relab
 		flags.MetricsFlags,
 		flags.InstanceRelationFlags,
 		flags.EndpointRelationFlags,
+		flags.ProcessRelationFlags,
 		[]cli.Flag{
 			&cli.StringFlag{
 				Name:     "labels",
@@ -71,6 +72,7 @@ $ swctl metrics multiple-linear --name all_percentile --labels=0,1,2,3,4 --relab
 		interceptor.DurationInterceptor,
 		interceptor.ParseEndpointRelation(false),
 		interceptor.ParseInstanceRelation(false),
+		interceptor.ParseProcessRelation(false),
 	),
 	Action: func(ctx *cli.Context) error {
 		end := ctx.String("end")
diff --git a/internal/commands/metrics/single/single-metrics.go b/internal/commands/metrics/single/single-metrics.go
index 9876485..f10dac5 100644
--- a/internal/commands/metrics/single/single-metrics.go
+++ b/internal/commands/metrics/single/single-metrics.go
@@ -46,11 +46,13 @@ $ swctl metrics single --name endpoint_cpm --service-name business-zone::project
 		flags.MetricsFlags,
 		flags.InstanceRelationFlags,
 		flags.EndpointRelationFlags,
+		flags.ProcessRelationFlags,
 	),
 	Before: interceptor.BeforeChain(
 		interceptor.DurationInterceptor,
 		interceptor.ParseEndpointRelation(false),
 		interceptor.ParseInstanceRelation(false),
+		interceptor.ParseProcessRelation(false),
 	),
 	Action: func(ctx *cli.Context) error {
 		end := ctx.String("end")
diff --git a/internal/commands/metrics/thermodynamic/thermodynamic.go b/internal/commands/metrics/thermodynamic/thermodynamic.go
index a34199b..dbc8303 100644
--- a/internal/commands/metrics/thermodynamic/thermodynamic.go
+++ b/internal/commands/metrics/thermodynamic/thermodynamic.go
@@ -45,11 +45,13 @@ $ swctl metrics thermodynamic --scope all --name all_heatmap
 		flags.MetricsFlags,
 		flags.InstanceRelationFlags,
 		flags.EndpointRelationFlags,
+		flags.ProcessRelationFlags,
 	),
 	Before: interceptor.BeforeChain(
 		interceptor.DurationInterceptor,
 		interceptor.ParseEndpointRelation(false),
 		interceptor.ParseInstanceRelation(false),
+		interceptor.ParseProcessRelation(false),
 	),
 	Action: func(ctx *cli.Context) error {
 		end := ctx.String("end")
diff --git a/internal/commands/profiling/ebpf/create/create.go b/internal/commands/profiling/ebpf/create/create.go
index bf233b1..e3829d4 100644
--- a/internal/commands/profiling/ebpf/create/create.go
+++ b/internal/commands/profiling/ebpf/create/create.go
@@ -25,5 +25,6 @@ var CreateCommand = &cli.Command{
 	Subcommands: []*cli.Command{
 		PrepareCreateCommand,
 		FixedTimeCreateCommand,
+		NetworkCreateCommand,
 	},
 }
diff --git a/internal/commands/metrics/thermodynamic/thermodynamic.go b/internal/commands/profiling/ebpf/create/network.go
similarity index 50%
copy from internal/commands/metrics/thermodynamic/thermodynamic.go
copy to internal/commands/profiling/ebpf/create/network.go
index a34199b..aadf2c8 100644
--- a/internal/commands/metrics/thermodynamic/thermodynamic.go
+++ b/internal/commands/profiling/ebpf/create/network.go
@@ -15,72 +15,49 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package thermodynamic
+package create
 
 import (
-	"github.com/urfave/cli/v2"
-
 	"github.com/apache/skywalking-cli/internal/commands/interceptor"
 	"github.com/apache/skywalking-cli/internal/flags"
-	"github.com/apache/skywalking-cli/internal/model"
 	"github.com/apache/skywalking-cli/pkg/display"
 	"github.com/apache/skywalking-cli/pkg/display/displayable"
-	"github.com/apache/skywalking-cli/pkg/graphql/metrics"
+	"github.com/apache/skywalking-cli/pkg/graphql/profiling"
+
+	"github.com/urfave/cli/v2"
 
 	api "skywalking.apache.org/repo/goapi/query"
 )
 
-var Command = &cli.Command{
-	Name:    "thermodynamic",
-	Aliases: []string{"td", "heatmap", "hp", "hm"},
-	Usage:   "query thermodynamic-type metrics defined in backend OAL",
-	UsageText: `Query the thermodynamic-type metrics defined in backend OAL.
+var NetworkCreateCommand = &cli.Command{
+	Name:    "network",
+	Aliases: []string{"net"},
+	Usage:   "Create a new ebpf network profiling task",
+	UsageText: `Create a new ebpf network profiling task
 
 Examples:
-1. Query the global heatmap:
-$ swctl metrics thermodynamic --scope all --name all_heatmap
-`,
+1. Create ebpf network profiling task
+$ swctl profiling ebpf create network --service-instance-id=abc`,
 	Flags: flags.Flags(
-		flags.DurationFlags,
-		flags.MetricsFlags,
-		flags.InstanceRelationFlags,
-		flags.EndpointRelationFlags,
+		flags.ServiceFlags,
+		flags.InstanceFlags,
 	),
 	Before: interceptor.BeforeChain(
-		interceptor.DurationInterceptor,
-		interceptor.ParseEndpointRelation(false),
-		interceptor.ParseInstanceRelation(false),
+		interceptor.ParseInstance(true),
 	),
 	Action: func(ctx *cli.Context) error {
-		end := ctx.String("end")
-		start := ctx.String("start")
-		step := ctx.Generic("step")
-
-		metricsName := ctx.String("name")
-		entity, err := interceptor.ParseEntity(ctx)
-		if err != nil {
-			return err
-		}
+		instanceID := ctx.String("instance-id")
 
-		duration := api.Duration{
-			Start: start,
-			End:   end,
-			Step:  step.(*model.StepEnumValue).Selected,
+		request := &api.EBPFProfilingNetworkTaskRequest{
+			InstanceID: instanceID,
 		}
 
-		metricsValues, err := metrics.Thermodynamic(ctx, api.MetricsCondition{
-			Name:   metricsName,
-			Entity: entity,
-		}, duration)
+		task, err := profiling.CreateEBPFNetworkProfilingTask(ctx, request)
 
 		if err != nil {
 			return err
 		}
 
-		return display.Display(ctx, &displayable.Displayable{
-			Data:     metricsValues,
-			Duration: duration,
-			Title:    metricsName,
-		})
+		return display.Display(ctx, &displayable.Displayable{Data: task, Condition: request})
 	},
 }
diff --git a/internal/commands/profiling/ebpf/ebpf.go b/internal/commands/profiling/ebpf/ebpf.go
index e9c9926..02c4262 100644
--- a/internal/commands/profiling/ebpf/ebpf.go
+++ b/internal/commands/profiling/ebpf/ebpf.go
@@ -19,6 +19,7 @@ package ebpf
 
 import (
 	"github.com/apache/skywalking-cli/internal/commands/profiling/ebpf/create"
+	"github.com/apache/skywalking-cli/internal/commands/profiling/ebpf/keep"
 
 	"github.com/urfave/cli/v2"
 )
@@ -28,6 +29,7 @@ var Command = &cli.Command{
 	Usage: "eBPF Profiling related sub-command",
 	Subcommands: []*cli.Command{
 		create.CreateCommand,
+		keep.KeepCommand,
 		ListTaskCommand,
 		ListScheduleCommand,
 		AnalyzationCommand,
diff --git a/internal/commands/profiling/ebpf/create/create.go b/internal/commands/profiling/ebpf/keep/keep.go
similarity index 83%
copy from internal/commands/profiling/ebpf/create/create.go
copy to internal/commands/profiling/ebpf/keep/keep.go
index bf233b1..22af29e 100644
--- a/internal/commands/profiling/ebpf/create/create.go
+++ b/internal/commands/profiling/ebpf/keep/keep.go
@@ -15,15 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package create
+package keep
 
 import "github.com/urfave/cli/v2"
 
-var CreateCommand = &cli.Command{
-	Name:  "create",
-	Usage: "eBPF Profiling task create related sub-command",
+var KeepCommand = &cli.Command{
+	Name:  "keep",
+	Usage: "eBPF Profiling task keep-alive related sub-command",
 	Subcommands: []*cli.Command{
-		PrepareCreateCommand,
-		FixedTimeCreateCommand,
+		NetworkKeepCommand,
 	},
 }
diff --git a/internal/commands/profiling/ebpf/keep/network.go b/internal/commands/profiling/ebpf/keep/network.go
new file mode 100644
index 0000000..8d86f6d
--- /dev/null
+++ b/internal/commands/profiling/ebpf/keep/network.go
@@ -0,0 +1,57 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package keep
+
+import (
+	"github.com/apache/skywalking-cli/internal/flags"
+	"github.com/apache/skywalking-cli/pkg/display"
+	"github.com/apache/skywalking-cli/pkg/display/displayable"
+	"github.com/apache/skywalking-cli/pkg/graphql/profiling"
+
+	"github.com/urfave/cli/v2"
+)
+
+var NetworkKeepCommand = &cli.Command{
+	Name:    "network",
+	Aliases: []string{"net"},
+	Usage:   "Keep alive the exist ebpf network profiling task",
+	UsageText: `Keep alive the exist ebpf network profiling task
+
+Examples:
+1. Keep alive the ebpf network profiling task
+$ swctl profiling ebpf keep network --task-id=abc`,
+	Flags: flags.Flags(
+		[]cli.Flag{
+			&cli.StringFlag{
+				Name:     "task-id",
+				Usage:    "the `task-id` of the network profiling task",
+				Required: true,
+			},
+		},
+	),
+	Action: func(ctx *cli.Context) error {
+		taskID := ctx.String("task-id")
+
+		keepResult, err := profiling.KeepNetworkProfilingTask(ctx, taskID)
+		if err != nil {
+			return err
+		}
+
+		return display.Display(ctx, &displayable.Displayable{Data: keepResult})
+	},
+}
diff --git a/internal/commands/profiling/ebpf/create/create.go b/internal/flags/process.go
similarity index 57%
copy from internal/commands/profiling/ebpf/create/create.go
copy to internal/flags/process.go
index bf233b1..8606059 100644
--- a/internal/commands/profiling/ebpf/create/create.go
+++ b/internal/flags/process.go
@@ -15,15 +15,32 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package create
+package flags
 
 import "github.com/urfave/cli/v2"
 
-var CreateCommand = &cli.Command{
-	Name:  "create",
-	Usage: "eBPF Profiling task create related sub-command",
-	Subcommands: []*cli.Command{
-		PrepareCreateCommand,
-		FixedTimeCreateCommand,
+// ProcessFlags take either process id or process name as input,
+// and transform to the other one.
+var ProcessFlags = []cli.Flag{
+	&cli.StringFlag{
+		Name:     "process-id",
+		Usage:    "`process id`, if you don't have process id, use `--process-name` instead",
+		Required: false,
+	},
+	&cli.StringFlag{
+		Name:     "process-name",
+		Usage:    "`process name`",
+		Required: false,
 	},
 }
+
+// ProcessRelationFlags take either destination process name as input,
+var ProcessRelationFlags = append(
+	ProcessFlags,
+
+	&cli.StringFlag{
+		Name:     "dest-process-name",
+		Usage:    "`destination` process name",
+		Required: false,
+	},
+)
diff --git a/pkg/graphql/dependency/dependency.go b/pkg/graphql/dependency/dependency.go
index dd189ca..ea5fe1a 100644
--- a/pkg/graphql/dependency/dependency.go
+++ b/pkg/graphql/dependency/dependency.go
@@ -63,3 +63,15 @@ func InstanceTopology(ctx *cli.Context, clientServiceID, serverServiceID string,
 
 	return response["result"], err
 }
+
+func ProcessTopology(ctx *cli.Context, instanceID string, duration api.Duration) (api.ProcessTopology, error) {
+	var response map[string]api.ProcessTopology
+
+	request := graphql.NewRequest(assets.Read("graphqls/dependency/ProcessTopology.graphql"))
+	request.Var("serviceInstanceId", instanceID)
+	request.Var("duration", duration)
+
+	err := client.ExecuteQuery(ctx, request, &response)
+
+	return response["result"], err
+}
diff --git a/pkg/graphql/profiling/ebpf.go b/pkg/graphql/profiling/ebpf.go
index 2d9c10c..c75e392 100644
--- a/pkg/graphql/profiling/ebpf.go
+++ b/pkg/graphql/profiling/ebpf.go
@@ -40,6 +40,17 @@ func CreateEBPFProfilingFixedTimeTask(ctx *cli.Context,
 	return response["result"], err
 }
 
+func CreateEBPFNetworkProfilingTask(ctx *cli.Context, condition *api.EBPFProfilingNetworkTaskRequest) (api.EBPFProfilingTaskCreationResult, error) {
+	var response map[string]api.EBPFProfilingTaskCreationResult
+
+	request := graphql.NewRequest(assets.Read("graphqls/profiling/ebpf/CreateEBPFNetworkProfilingTask.graphql"))
+	request.Var("request", condition)
+
+	err := client.ExecuteQuery(ctx, request, &response)
+
+	return response["result"], err
+}
+
 func QueryPrepareCreateEBPFProfilingTaskData(ctx *cli.Context, serviceID string) (*api.EBPFProfilingTaskPrepare, error) {
 	var response map[string]*api.EBPFProfilingTaskPrepare
 
@@ -86,3 +97,14 @@ func AnalysisEBPFProfilingResult(ctx *cli.Context, scheduleIDList []string,
 
 	return response["result"], err
 }
+
+func KeepNetworkProfilingTask(ctx *cli.Context, taskID string) (*api.EBPFNetworkKeepProfilingResult, error) {
+	var response map[string]*api.EBPFNetworkKeepProfilingResult
+
+	request := graphql.NewRequest(assets.Read("graphqls/profiling/ebpf/KeepNetworkProfilingTask.graphql"))
+	request.Var("taskId", taskID)
+
+	err := client.ExecuteQuery(ctx, request, &response)
+
+	return response["result"], err
+}
diff --git a/pkg/graphql/utils/parser.go b/pkg/graphql/utils/parser.go
index 037cedd..15925c5 100644
--- a/pkg/graphql/utils/parser.go
+++ b/pkg/graphql/utils/parser.go
@@ -27,7 +27,9 @@ import (
 func ParseScope(entity *api.Entity) api.Scope {
 	scope := api.ScopeAll
 
-	if *entity.DestEndpointName != "" {
+	if *entity.DestProcessName != "" {
+		scope = api.ScopeProcessRelation
+	} else if *entity.DestEndpointName != "" {
 		scope = api.ScopeEndpointRelation
 	} else if *entity.DestServiceInstanceName != "" {
 		scope = api.ScopeServiceInstanceRelation
diff --git a/pkg/graphql/utils/parser_test.go b/pkg/graphql/utils/parser_test.go
index 9128979..9adb020 100644
--- a/pkg/graphql/utils/parser_test.go
+++ b/pkg/graphql/utils/parser_test.go
@@ -23,6 +23,7 @@ import (
 	api "skywalking.apache.org/repo/goapi/query"
 )
 
+//nolint:funlen // disable function length check for the test case count
 func TestParseScope(t *testing.T) {
 	empty := ""
 	nonEmpty := "test"
@@ -37,9 +38,11 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &empty,
 				ServiceInstanceName:     &empty,
 				EndpointName:            &empty,
+				ProcessName:             &empty,
 				DestServiceName:         &empty,
 				DestServiceInstanceName: &empty,
 				DestEndpointName:        &empty,
+				DestProcessName:         &empty,
 			},
 			want: api.ScopeAll,
 		},
@@ -49,11 +52,13 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &nonEmpty,
 				ServiceInstanceName:     &nonEmpty,
 				EndpointName:            &nonEmpty,
+				ProcessName:             &nonEmpty,
 				DestServiceName:         &nonEmpty,
 				DestServiceInstanceName: &nonEmpty,
 				DestEndpointName:        &nonEmpty,
+				DestProcessName:         &nonEmpty,
 			},
-			want: api.ScopeEndpointRelation,
+			want: api.ScopeProcessRelation,
 		},
 		{
 			name: "only serviceName is not empty",
@@ -61,9 +66,11 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &nonEmpty,
 				ServiceInstanceName:     &empty,
 				EndpointName:            &empty,
+				ProcessName:             &empty,
 				DestServiceName:         &empty,
 				DestServiceInstanceName: &empty,
 				DestEndpointName:        &empty,
+				DestProcessName:         &empty,
 			},
 			want: api.ScopeService,
 		},
@@ -73,9 +80,11 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &nonEmpty,
 				ServiceInstanceName:     &nonEmpty,
 				EndpointName:            &empty,
+				ProcessName:             &empty,
 				DestServiceName:         &empty,
 				DestServiceInstanceName: &empty,
 				DestEndpointName:        &empty,
+				DestProcessName:         &empty,
 			},
 			want: api.ScopeServiceInstance,
 		},
@@ -85,9 +94,11 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &nonEmpty,
 				ServiceInstanceName:     &empty,
 				EndpointName:            &nonEmpty,
+				ProcessName:             &empty,
 				DestServiceName:         &empty,
 				DestServiceInstanceName: &empty,
 				DestEndpointName:        &empty,
+				DestProcessName:         &empty,
 			},
 			want: api.ScopeEndpoint,
 		},
@@ -97,9 +108,11 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &nonEmpty,
 				ServiceInstanceName:     &empty,
 				EndpointName:            &empty,
+				ProcessName:             &empty,
 				DestServiceName:         &nonEmpty,
 				DestServiceInstanceName: &empty,
 				DestEndpointName:        &empty,
+				DestProcessName:         &empty,
 			},
 			want: api.ScopeServiceRelation,
 		},
@@ -109,12 +122,28 @@ func TestParseScope(t *testing.T) {
 				ServiceName:             &nonEmpty,
 				ServiceInstanceName:     &nonEmpty,
 				EndpointName:            &empty,
+				ProcessName:             &empty,
 				DestServiceName:         &nonEmpty,
 				DestServiceInstanceName: &nonEmpty,
 				DestEndpointName:        &empty,
+				DestProcessName:         &empty,
 			},
 			want: api.ScopeServiceInstanceRelation,
 		},
+		{
+			name: "destProcess is not empty",
+			args: &api.Entity{
+				ServiceName:             &nonEmpty,
+				ServiceInstanceName:     &nonEmpty,
+				EndpointName:            &empty,
+				ProcessName:             &nonEmpty,
+				DestServiceName:         &nonEmpty,
+				DestServiceInstanceName: &nonEmpty,
+				DestEndpointName:        &empty,
+				DestProcessName:         &nonEmpty,
+			},
+			want: api.ScopeProcessRelation,
+		},
 	}
 
 	for _, tt := range tests {