diff --git a/CHANGES.md b/CHANGES.md index 76d865bd..fea6fa60 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,6 +33,7 @@ Release Notes. * 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 d9b8a30f..a9a7c66e 100644 --- a/dist/LICENSE +++ b/dist/LICENSE @@ -213,7 +213,7 @@ The text of each license is also included at licenses/license-[project].txt. 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 00000000..4d865615 --- /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: string. The match pattern for HTTP request. This is HTTP URI-oriented. matches all requests if not set +# min_duration: int(ms). The minimal request duration to activate the network data(HTTP request/response raw data) sampling. +# when_4xx: bool. Collecting requests when the response code is 400-499. +# when_5xx: bool. Collecting requests when the response code is 500-599. +# setting: define how to collect sampled data +# require_request: bool. Require to collect the complete request. +# max_request_size: int. The max size of request context. The unit is byte. +# require_response: bool. Require to collect the complete response. +# max_response_size: 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 a5becccd..a86f33f4 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( 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 4bc7dae3..5204896a 100644 --- a/go.sum +++ b/go.sum @@ -857,5 +857,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3 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 aadf2c8f..b30c86b8 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 @@ $ swctl profiling ebpf create network --service-instance-id=abc`, 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 @@ $ swctl profiling ebpf create network --service-instance-id=abc`, 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 @@ $ swctl profiling ebpf create network --service-instance-id=abc`, 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 +}