Support sampling config in network profiling (#171)

diff --git a/CHANGES.md b/CHANGES.md
index 76d865b..fea6fa6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -33,6 +33,7 @@
 * Add compatibility documentation by @mrproliu in https://github.com/apache/skywalking-cli/pull/164
 * Add the sub-command `records list` for adapt the new record query API by @mrproliu in https://github.com/apache/skywalking-cli/pull/167
 * Add the attached events fields into the `trace` sub-command by @mrproliu in https://github.com/apache/skywalking-cli/pull/169
+* Add the sampling config file into the `profiling ebpf create network` sub-command by @mrproliu in https://github.com/apache/skywalking-cli/pull/171
 
 0.10.0
 ------------------
diff --git a/dist/LICENSE b/dist/LICENSE
index d9b8a30..a9a7c66 100644
--- a/dist/LICENSE
+++ b/dist/LICENSE
@@ -213,7 +213,7 @@
     k8s.io/utils v0.0.0-20210802155522-efc7438f0176 Apache-2.0
     sigs.k8s.io/controller-runtime v0.10.0 Apache-2.0
     sigs.k8s.io/structured-merge-diff/v4 v4.1.2 Apache-2.0
-    skywalking.apache.org/repo/goapi v0.0.0-20221019074310-53ebda305187 Apache-2.0
+    skywalking.apache.org/repo/goapi v0.0.0-20221123034834-51b3101f6c9f Apache-2.0
 
 ========================================================================
 BSD-2-Clause licenses
diff --git a/examples/network-sampling.yaml b/examples/network-sampling.yaml
new file mode 100644
index 0000000..4d86561
--- /dev/null
+++ b/examples/network-sampling.yaml
@@ -0,0 +1,49 @@
+# Licensed to the 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.  The 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.
+
+# The command `dashboard global` supports displaying three kinds of data:
+# `global metrics`, `global response latency`, `Global heat map`.
+# If you don't want to display an item, you can just delete or comment its whole configuration below.
+# Generally, there is no need to modify properties unless there is a explanatory comment.
+
+# Sampling config
+# samplings: the sampling config list
+# - uri_pattern: <optional> string. The match pattern for HTTP request. This is HTTP URI-oriented. matches all requests if not set
+#   min_duration: <optional> int(ms). The minimal request duration to activate the network data(HTTP request/response raw data) sampling.
+#   when_4xx: <required> bool. Collecting requests when the response code is 400-499.
+#   when_5xx: <required> bool. Collecting requests when the response code is 500-599.
+#   setting: define how to collect sampled data
+#     require_request: <required> bool. Require to collect the complete request.
+#     max_request_size: <optional> int. The max size of request context. The unit is byte.
+#     require_response: <required> bool. Require to collect the complete response.
+#     max_response_size: <optional> int. The max size of response context. The unit is byte.
+
+samplings:
+  # define collecting full request data when the response code is 400-499 and 500-599 .
+  - when_4xx: true
+    when_5xx: true
+    setting:
+      require_request: true
+      require_response: false
+  # define collecting first 1KB response data when the response code is 500-599 and the duration bigger than or equals 10ms.
+  - uri_pattern: /index.html
+    when_4xx: false
+    when_5xx: true
+    min_duration: 10
+    setting:
+      require_request: false
+      require_response: true
+      max_response_size: 1024
\ No newline at end of file
diff --git a/go.mod b/go.mod
index a5beccc..a86f33f 100644
--- a/go.mod
+++ b/go.mod
@@ -20,7 +20,7 @@
 	gopkg.in/yaml.v2 v2.4.0
 	k8s.io/apimachinery v0.22.1
 	sigs.k8s.io/controller-runtime v0.10.0
-	skywalking.apache.org/repo/goapi v0.0.0-20221019074310-53ebda305187
+	skywalking.apache.org/repo/goapi v0.0.0-20221123034834-51b3101f6c9f
 )
 
 require (
diff --git a/go.sum b/go.sum
index 4bc7dae..5204896 100644
--- a/go.sum
+++ b/go.sum
@@ -857,5 +857,5 @@
 sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
 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-20221019074310-53ebda305187 h1:6JgAg9aohcHd72VplZUGycZgCNo6iQrz735nmtOTCnE=
-skywalking.apache.org/repo/goapi v0.0.0-20221019074310-53ebda305187/go.mod h1:lxmYWY1uAP5SLVKNymAyDzn7KG6dhPWN+pYHmyt+0vo=
+skywalking.apache.org/repo/goapi v0.0.0-20221123034834-51b3101f6c9f h1:iRQHKYsca0gbSxGWFjlkQ/WIuLyKReFUk2PscgzBqAw=
+skywalking.apache.org/repo/goapi v0.0.0-20221123034834-51b3101f6c9f/go.mod h1:lxmYWY1uAP5SLVKNymAyDzn7KG6dhPWN+pYHmyt+0vo=
diff --git a/internal/commands/profiling/ebpf/create/network.go b/internal/commands/profiling/ebpf/create/network.go
index aadf2c8..b30c86b 100644
--- a/internal/commands/profiling/ebpf/create/network.go
+++ b/internal/commands/profiling/ebpf/create/network.go
@@ -18,17 +18,41 @@
 package create
 
 import (
+	"fmt"
+	"os"
+
 	"github.com/apache/skywalking-cli/internal/commands/interceptor"
 	"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"
 
+	"gopkg.in/yaml.v2"
+
 	"github.com/urfave/cli/v2"
 
 	api "skywalking.apache.org/repo/goapi/query"
 )
 
+type SamplingConfig struct {
+	Samplings []*SamplingRule `yaml:"samplings"`
+}
+
+type SamplingRule struct {
+	URIPattern  *string          `yaml:"uri_pattern"`
+	MinDuration *int             `yaml:"min_duration"`
+	When4xx     *bool            `yaml:"when_4xx"`
+	When5xx     *bool            `yaml:"when_5xx"`
+	Setting     *SamplingSetting `yaml:"setting"`
+}
+
+type SamplingSetting struct {
+	RequireRequest  *bool `yaml:"require_request"`
+	MaxRequestSize  *int  `yaml:"max_request_size"`
+	RequireResponse *bool `yaml:"require_response"`
+	MaxResponseSize *int  `yaml:"max_response_size"`
+}
+
 var NetworkCreateCommand = &cli.Command{
 	Name:    "network",
 	Aliases: []string{"net"},
@@ -41,6 +65,13 @@
 	Flags: flags.Flags(
 		flags.ServiceFlags,
 		flags.InstanceFlags,
+		[]cli.Flag{
+			&cli.StringFlag{
+				Name:     "sampling-config",
+				Usage:    "the `sampling-config` file define how to sampling the network data, if not then then ignore data sampling",
+				Required: false,
+			},
+		},
 	),
 	Before: interceptor.BeforeChain(
 		interceptor.ParseInstance(true),
@@ -48,8 +79,29 @@
 	Action: func(ctx *cli.Context) error {
 		instanceID := ctx.String("instance-id")
 
+		samplingConfigFile := ctx.String("sampling-config")
+
+		// convert the sampling rule
+		var samplings = make([]*api.EBPFNetworkSamplingRule, 0)
+		if samplingConfigFile != "" {
+			config, err := os.ReadFile(samplingConfigFile)
+			if err != nil {
+				return err
+			}
+			r := &SamplingConfig{}
+			if e := yaml.Unmarshal(config, r); e != nil {
+				return e
+			}
+
+			samplings, err = parsingNetworkSampling(r)
+			if err != nil {
+				return err
+			}
+		}
+
 		request := &api.EBPFProfilingNetworkTaskRequest{
 			InstanceID: instanceID,
+			Samplings:  samplings,
 		}
 
 		task, err := profiling.CreateEBPFNetworkProfilingTask(ctx, request)
@@ -61,3 +113,44 @@
 		return display.Display(ctx, &displayable.Displayable{Data: task, Condition: request})
 	},
 }
+
+func parsingNetworkSampling(config *SamplingConfig) ([]*api.EBPFNetworkSamplingRule, error) {
+	rules := make([]*api.EBPFNetworkSamplingRule, 0)
+	if config == nil || len(config.Samplings) == 0 {
+		return rules, nil
+	}
+	for _, conf := range config.Samplings {
+		rule := &api.EBPFNetworkSamplingRule{}
+		rule.URIRegex = conf.URIPattern
+		rule.MinDuration = conf.MinDuration
+		if conf.When4xx == nil {
+			return nil, fmt.Errorf("the when_4xx is required")
+		}
+		rule.When4xx = *conf.When4xx
+		if conf.When5xx == nil {
+			return nil, fmt.Errorf("the when_5xx is required")
+		}
+		rule.When5xx = *conf.When5xx
+
+		confSetting := conf.Setting
+		if confSetting == nil {
+			return nil, fmt.Errorf("the sampling settings is required")
+		}
+		setting := &api.EBPFNetworkDataCollectingSettings{}
+		rule.Settings = setting
+		if confSetting.RequireRequest == nil {
+			return nil, fmt.Errorf("the sampling request is required")
+		}
+		setting.RequireCompleteRequest = *confSetting.RequireRequest
+		setting.MaxRequestSize = confSetting.MaxRequestSize
+		if confSetting.RequireResponse == nil {
+			return nil, fmt.Errorf("the sampling response is required")
+		}
+		setting.RequireCompleteResponse = *confSetting.RequireResponse
+		setting.MaxResponseSize = confSetting.MaxResponseSize
+
+		rules = append(rules, rule)
+	}
+
+	return rules, nil
+}