You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by li...@apache.org on 2021/08/01 05:06:05 UTC
[skywalking-cli] branch master updated: Profile command support
(#104)
This is an automated email from the ASF dual-hosted git repository.
liuhan 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 fd89634 Profile command support (#104)
fd89634 is described below
commit fd896344969a366786bf45ead2f23e230b61b6b9
Author: mrproliu <74...@qq.com>
AuthorDate: Sun Aug 1 13:05:59 2021 +0800
Profile command support (#104)
* Support profile protocol
Co-authored-by: Mrproliu <mr...@lagou.com>
---
README.md | 110 +++++++++
assets/assets.gen.go | 255 +++++++++++++++++++++
assets/graphqls/profile/CreateTask.graphql | 23 ++
assets/graphqls/profile/GetProfileAnalyze.graphql | 31 +++
assets/graphqls/profile/GetProfiledSegment.graphql | 37 +++
assets/graphqls/profile/GetTaskList.graphql | 35 +++
assets/graphqls/profile/GetTaskSegmentList.graphql | 27 +++
cmd/swctl/main.go | 2 +
internal/commands/profile/create.go | 106 +++++++++
internal/commands/profile/getProfileAnalyze.go | 78 +++++++
internal/commands/profile/getProfiledSegment.go | 50 ++++
internal/commands/profile/getTaskList.go | 75 ++++++
internal/commands/profile/getTaskSegmentList.go | 50 ++++
internal/commands/profile/profile.go | 34 +++
pkg/graphql/profile/profile.go | 86 +++++++
15 files changed, 999 insertions(+)
diff --git a/README.md b/README.md
index 48837c7..1648d3b 100644
--- a/README.md
+++ b/README.md
@@ -418,6 +418,78 @@ You can imitate the content of [the default template file](examples/global.yml)
</details>
+### `profile`
+
+#### `create`
+
+<details>
+
+<summary>profile create [--service-id=service-id] [--service-name=service-name] [--endpoint=endpoint] [--start-time=start-time] [--duration=duration] [--min-duration-threshold=min-duration-threshold] [--dump-period=dump-period] [--max-sampling-count=max-sampling-count] </summary>
+
+| argument | description | default |
+| :--- | :--- | :--- |
+| `service-id` | <service-id> whose endpoints are to be profile. | |
+| `service-name` | <service-name> whose endpoints are to be profile. | |
+| `endpoint` | which endpoint should profile. | |
+| `start-time` | profile task start time(millisecond). | |
+| `duration` | profile task continuous time(minute). | |
+| `min-duration-threshold` | profiled endpoint must greater duration(millisecond). | |
+| `dump-period` | profiled endpoint dump period(millisecond). | |
+| `max-sampling-count` | profile task max sampling count. | |
+
+</details>
+
+#### `list`
+
+<details>
+
+<summary>profile list [--service-id=service-id] [--service-name=service-name] [--endpoint=endpoint] </summary>
+
+| argument | description | default |
+| :--- | :--- | :--- |
+| `service-id` | `<service id>` whose profile task are to be searched. | |
+| `service-name` | `<service name>` whose profile task are to be searched. | |
+| `endpoint` | `<endpoint>` whose profile task are to be searched | |
+
+</details>
+
+#### `segment-list`
+
+<details>
+
+<summary>profile segment-list [--task-id=task-id] </summary>
+
+| argument | description | default |
+| :--- | :--- | :--- |
+| `task-id` | `<task id>` whose profiled segment are to be searched. | |
+
+</details>
+
+#### `profiled-segment`
+
+<details>
+
+<summary>profile profiled-segment [--segment-id=segment-id] </summary>
+
+| argument | description | default |
+| :--- | :--- | :--- |
+| `segment-id` | profiled segment id. | |
+
+</details>
+
+#### `profiled-analyze`
+
+<details>
+
+<summary>profile profiled-analyze [--segment-id=segment-id] [--time-ranges=time-ranges] </summary>
+
+| argument | description | default |
+| :--- | :--- | :--- |
+| `segment-id` | profiled segment id. | |
+| `time-ranges` | need to analyze time ranges in the segment: start-end,start-end. | |
+
+</details>
+
# Use Cases
<details>
@@ -600,6 +672,44 @@ $ ./bin/swctl logs list
<details>
+<summary>Profile the endpoint</summary>
+
+If your endpoint has performance issue and could not use tracing to find out what's happen, you could try to profile. You could get more information on [this page](https://github.com/apache/skywalking/blob/master/docs/en/guides/backend-profile.md).
+
+create profile task.
+```shell
+$ ./bin/swctl profile create --service-name=service-name --endpoint=endpoint --start-time=1627656127860 --duration=5 --min-duration-threshold=0 --dump-period=10 --max-sampling-count=9
+{"errorReason":null,"id":"1627740677560_ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1"}
+```
+
+Query existing task and logs.
+```shell
+$ ./bin/swctl profile list --service-name=service-name --endpoint=endpoint
+[{"id":"1627740677560_ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1","serviceId":"ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1","serviceName":"","endpointName":"/info","startTime":1627740917933,"duration":5,"minDurationThreshold":0,"dumpPeriod":10,"maxSamplingCount":9,"logs":[{"id":"1627740677560_ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1_ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1_cHJvdmlkZXIx_1_1627740682470","instanceId":"ZTJlLXNlcnZpY2UtcHJvdmlkZXI=.1_cHJvdmlkZXIx","instanceName":"","operationType":"NOTIFIED","operationTime":1627740682470}]}]
+```
+
+Query profiled segment list.
+```shell
+$ ./bin/swctl profile segment-list --service-name=service-name --endpoint=endpoint
+[{"segmentId":"8f7e9e21221d427cb684a60d352a47ef.71.16277409290420002","endpointNames":["/info"],"duration":603,"start":"1627740929042","isError":false,"traceIds":["8f7e9e21221d427cb684a60d352a47ef.71.16277409290420003"]}]
+```
+
+Query profiled segment spans.
+```shell
+$ ./bin/swctl profile profiled-segment --segment-id=segment-id
+{"spans":[{"spanId":0,"parentSpanId":-1,"serviceCode":"e2e-service-provider","serviceInstanceName":"","startTime":1627740929042,"endTime":1627740929645,"endpointName":"/info","type":"Entry","peer":"","component":"Tomcat","isError":false,"layer":"Http","tags":[{"key":"url","value":"http://localhost:49553/info"},{"key":"http.method","value":"POST"}],"logs":null}]}
+```
+
+Analyze profiled segment with time ranges.
+```shell
+$ ./bin/swctl profile profiled-segment --segment-id=segment-id --time-ranges=start-end
+{"tip":null,"trees":[{"elements":[{"id":"1","parentId":"0","codeSignature":"java.lang.Thread.run:748","duration":577,"durationChildExcluded":0,"count":56},{"id":"2","parentId":"1","codeSignature":"org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run:61","duration":577,"durationChildExcluded":0,"count":56}]}]}
+```
+
+</details>
+
+<details>
+
<summary>Display the spans of a trace</summary>
```shell
diff --git a/assets/assets.gen.go b/assets/assets.gen.go
index dca3aab..86a8b42 100644
--- a/assets/assets.gen.go
+++ b/assets/assets.gen.go
@@ -32,6 +32,11 @@
// graphqls/metrics/MetricsValue.graphql (943B)
// graphqls/metrics/MetricsValues.graphql (1.05kB)
// graphqls/metrics/SortMetrics.graphql (969B)
+// graphqls/profile/CreateTask.graphql (971B)
+// graphqls/profile/GetProfileAnalyze.graphql (1.161kB)
+// graphqls/profile/GetProfiledSegment.graphql (1.2kB)
+// graphqls/profile/GetTaskList.graphql (1.212kB)
+// graphqls/profile/GetTaskSegmentList.graphql (1.002kB)
// graphqls/trace/Trace.graphql (1.518kB)
// graphqls/trace/Traces.graphql (1.077kB)
// templates/dashboard/global.yml (3.001kB)
@@ -712,6 +717,244 @@ func graphqlsMetricsSortmetricsGraphql() (*asset, error) {
return a, nil
}
+var _graphqlsProfileCreatetaskGraphql = []byte(`# 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 ($condition: ProfileTaskCreationRequest) {
+ result: createProfileTask(creationRequest: $condition) {
+ errorReason: errorReason
+ id: id
+ }
+}
+`)
+
+func graphqlsProfileCreatetaskGraphqlBytes() ([]byte, error) {
+ return _graphqlsProfileCreatetaskGraphql, nil
+}
+
+func graphqlsProfileCreatetaskGraphql() (*asset, error) {
+ bytes, err := graphqlsProfileCreatetaskGraphqlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "graphqls/profile/CreateTask.graphql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x4f, 0xcc, 0x41, 0xa2, 0xe6, 0x43, 0x55, 0xfb, 0x37, 0x34, 0x52, 0x74, 0x8c, 0xf3, 0x96, 0x2d, 0x14, 0x43, 0x5e, 0x3c, 0x5a, 0xf1, 0xc2, 0x3b, 0x45, 0xaf, 0xf2, 0xd2, 0xb, 0xbe, 0x38, 0xaf}}
+ return a, nil
+}
+
+var _graphqlsProfileGetprofileanalyzeGraphql = []byte(`# 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 ($segmentId: String!, $timeRanges: [ProfileAnalyzeTimeRange!]!) {
+ result: getProfileAnalyze(segmentId: $segmentId, timeRanges: $timeRanges) {
+ trees {
+ elements {
+ id
+ parentId
+ codeSignature
+ duration
+ durationChildExcluded
+ count
+ }
+ }
+ }
+}
+`)
+
+func graphqlsProfileGetprofileanalyzeGraphqlBytes() ([]byte, error) {
+ return _graphqlsProfileGetprofileanalyzeGraphql, nil
+}
+
+func graphqlsProfileGetprofileanalyzeGraphql() (*asset, error) {
+ bytes, err := graphqlsProfileGetprofileanalyzeGraphqlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "graphqls/profile/GetProfileAnalyze.graphql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xf6, 0x37, 0x86, 0xaa, 0x43, 0x4b, 0x29, 0x39, 0x2b, 0xee, 0xdb, 0x51, 0x22, 0xb9, 0xf8, 0xd6, 0x8a, 0x96, 0x5d, 0xe1, 0xb1, 0x8c, 0xd3, 0x1e, 0xe1, 0x6, 0x63, 0xdd, 0x51, 0x5b, 0xfa, 0x1d}}
+ return a, nil
+}
+
+var _graphqlsProfileGetprofiledsegmentGraphql = []byte(`# 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 ($segmentId: String!) {
+ result: getProfiledSegment(segmentId: $segmentId) {
+ spans {
+ spanId
+ parentSpanId
+ serviceCode
+ startTime
+ endTime
+ endpointName
+ type
+ peer
+ component
+ isError
+ layer
+ tags {
+ key value
+ }
+ }
+ }
+}
+`)
+
+func graphqlsProfileGetprofiledsegmentGraphqlBytes() ([]byte, error) {
+ return _graphqlsProfileGetprofiledsegmentGraphql, nil
+}
+
+func graphqlsProfileGetprofiledsegmentGraphql() (*asset, error) {
+ bytes, err := graphqlsProfileGetprofiledsegmentGraphqlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "graphqls/profile/GetProfiledSegment.graphql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe8, 0xf1, 0xcb, 0x40, 0xbc, 0x1f, 0xc7, 0x7a, 0xa, 0x57, 0x29, 0x4b, 0x1c, 0xdd, 0x48, 0x7c, 0x81, 0x5b, 0xed, 0x80, 0xf2, 0x3, 0xc3, 0xa4, 0x7, 0x18, 0x90, 0x55, 0xe8, 0x6, 0x21, 0xf7}}
+ return a, nil
+}
+
+var _graphqlsProfileGettasklistGraphql = []byte(`# 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 ($serviceId: ID, $endpointName: String) {
+ result: getProfileTaskList(serviceId: $serviceId, endpointName: $endpointName) {
+ id
+ serviceId
+ endpointName
+ startTime
+ duration
+ minDurationThreshold
+ dumpPeriod
+ maxSamplingCount
+ logs {
+ id
+ instanceId
+ operationType
+ operationTime
+ }
+ }
+}
+`)
+
+func graphqlsProfileGettasklistGraphqlBytes() ([]byte, error) {
+ return _graphqlsProfileGettasklistGraphql, nil
+}
+
+func graphqlsProfileGettasklistGraphql() (*asset, error) {
+ bytes, err := graphqlsProfileGettasklistGraphqlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "graphqls/profile/GetTaskList.graphql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe8, 0xf0, 0x74, 0x1, 0xe2, 0xbb, 0x9c, 0x3e, 0xc5, 0x29, 0x7e, 0x8f, 0x6b, 0x4a, 0x50, 0x21, 0xc3, 0xb, 0x28, 0x6c, 0x65, 0x5a, 0xcc, 0x51, 0x8e, 0x3e, 0x10, 0xc0, 0x85, 0xec, 0x68, 0x82}}
+ return a, nil
+}
+
+var _graphqlsProfileGettasksegmentlistGraphql = []byte(`# 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 ($taskId: String!) {
+ result: getProfileTaskSegmentList(taskID: $taskId) {
+ segmentId
+ endpointNames
+ duration
+ start
+ isError
+ traceIds
+ }
+}
+`)
+
+func graphqlsProfileGettasksegmentlistGraphqlBytes() ([]byte, error) {
+ return _graphqlsProfileGettasksegmentlistGraphql, nil
+}
+
+func graphqlsProfileGettasksegmentlistGraphql() (*asset, error) {
+ bytes, err := graphqlsProfileGettasksegmentlistGraphqlBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ info := bindataFileInfo{name: "graphqls/profile/GetTaskSegmentList.graphql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
+ a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xbb, 0xac, 0x15, 0xf8, 0x73, 0x38, 0x2f, 0xc, 0xdf, 0xcb, 0x2b, 0x43, 0x16, 0x30, 0x9d, 0x3e, 0xbf, 0x47, 0x0, 0x88, 0x35, 0x4c, 0x9b, 0xfa, 0x7, 0x5d, 0x32, 0x5, 0xbf, 0x51, 0x31, 0xdc}}
+ return a, nil
+}
+
var _graphqlsTraceTraceGraphql = []byte(`# 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
@@ -1040,6 +1283,11 @@ var _bindata = map[string]func() (*asset, error){
"graphqls/metrics/MetricsValue.graphql": graphqlsMetricsMetricsvalueGraphql,
"graphqls/metrics/MetricsValues.graphql": graphqlsMetricsMetricsvaluesGraphql,
"graphqls/metrics/SortMetrics.graphql": graphqlsMetricsSortmetricsGraphql,
+ "graphqls/profile/CreateTask.graphql": graphqlsProfileCreatetaskGraphql,
+ "graphqls/profile/GetProfileAnalyze.graphql": graphqlsProfileGetprofileanalyzeGraphql,
+ "graphqls/profile/GetProfiledSegment.graphql": graphqlsProfileGetprofiledsegmentGraphql,
+ "graphqls/profile/GetTaskList.graphql": graphqlsProfileGettasklistGraphql,
+ "graphqls/profile/GetTaskSegmentList.graphql": graphqlsProfileGettasksegmentlistGraphql,
"graphqls/trace/Trace.graphql": graphqlsTraceTraceGraphql,
"graphqls/trace/Traces.graphql": graphqlsTraceTracesGraphql,
"templates/dashboard/global.yml": templatesDashboardGlobalYml,
@@ -1115,6 +1363,13 @@ var _bintree = &bintree{nil, map[string]*bintree{
"MetricsValues.graphql": &bintree{graphqlsMetricsMetricsvaluesGraphql, map[string]*bintree{}},
"SortMetrics.graphql": &bintree{graphqlsMetricsSortmetricsGraphql, map[string]*bintree{}},
}},
+ "profile": &bintree{nil, map[string]*bintree{
+ "CreateTask.graphql": &bintree{graphqlsProfileCreatetaskGraphql, map[string]*bintree{}},
+ "GetProfileAnalyze.graphql": &bintree{graphqlsProfileGetprofileanalyzeGraphql, map[string]*bintree{}},
+ "GetProfiledSegment.graphql": &bintree{graphqlsProfileGetprofiledsegmentGraphql, map[string]*bintree{}},
+ "GetTaskList.graphql": &bintree{graphqlsProfileGettasklistGraphql, map[string]*bintree{}},
+ "GetTaskSegmentList.graphql": &bintree{graphqlsProfileGettasksegmentlistGraphql, map[string]*bintree{}},
+ }},
"trace": &bintree{nil, map[string]*bintree{
"Trace.graphql": &bintree{graphqlsTraceTraceGraphql, map[string]*bintree{}},
"Traces.graphql": &bintree{graphqlsTraceTracesGraphql, map[string]*bintree{}},
diff --git a/assets/graphqls/profile/CreateTask.graphql b/assets/graphqls/profile/CreateTask.graphql
new file mode 100644
index 0000000..0ab38df
--- /dev/null
+++ b/assets/graphqls/profile/CreateTask.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 ($condition: ProfileTaskCreationRequest) {
+ result: createProfileTask(creationRequest: $condition) {
+ errorReason: errorReason
+ id: id
+ }
+}
diff --git a/assets/graphqls/profile/GetProfileAnalyze.graphql b/assets/graphqls/profile/GetProfileAnalyze.graphql
new file mode 100644
index 0000000..49af788
--- /dev/null
+++ b/assets/graphqls/profile/GetProfileAnalyze.graphql
@@ -0,0 +1,31 @@
+# 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 ($segmentId: String!, $timeRanges: [ProfileAnalyzeTimeRange!]!) {
+ result: getProfileAnalyze(segmentId: $segmentId, timeRanges: $timeRanges) {
+ trees {
+ elements {
+ id
+ parentId
+ codeSignature
+ duration
+ durationChildExcluded
+ count
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/assets/graphqls/profile/GetProfiledSegment.graphql b/assets/graphqls/profile/GetProfiledSegment.graphql
new file mode 100644
index 0000000..98214bf
--- /dev/null
+++ b/assets/graphqls/profile/GetProfiledSegment.graphql
@@ -0,0 +1,37 @@
+# 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 ($segmentId: String!) {
+ result: getProfiledSegment(segmentId: $segmentId) {
+ spans {
+ spanId
+ parentSpanId
+ serviceCode
+ startTime
+ endTime
+ endpointName
+ type
+ peer
+ component
+ isError
+ layer
+ tags {
+ key value
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/assets/graphqls/profile/GetTaskList.graphql b/assets/graphqls/profile/GetTaskList.graphql
new file mode 100644
index 0000000..17f32ca
--- /dev/null
+++ b/assets/graphqls/profile/GetTaskList.graphql
@@ -0,0 +1,35 @@
+# 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 ($serviceId: ID, $endpointName: String) {
+ result: getProfileTaskList(serviceId: $serviceId, endpointName: $endpointName) {
+ id
+ serviceId
+ endpointName
+ startTime
+ duration
+ minDurationThreshold
+ dumpPeriod
+ maxSamplingCount
+ logs {
+ id
+ instanceId
+ operationType
+ operationTime
+ }
+ }
+}
\ No newline at end of file
diff --git a/assets/graphqls/profile/GetTaskSegmentList.graphql b/assets/graphqls/profile/GetTaskSegmentList.graphql
new file mode 100644
index 0000000..9d4e474
--- /dev/null
+++ b/assets/graphqls/profile/GetTaskSegmentList.graphql
@@ -0,0 +1,27 @@
+# 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 ($taskId: String!) {
+ result: getProfileTaskSegmentList(taskID: $taskId) {
+ segmentId
+ endpointNames
+ duration
+ start
+ isError
+ traceIds
+ }
+}
\ No newline at end of file
diff --git a/cmd/swctl/main.go b/cmd/swctl/main.go
index de5759f..bfbe23e 100644
--- a/cmd/swctl/main.go
+++ b/cmd/swctl/main.go
@@ -30,6 +30,7 @@ import (
"github.com/apache/skywalking-cli/internal/commands/interceptor"
"github.com/apache/skywalking-cli/internal/commands/logs"
"github.com/apache/skywalking-cli/internal/commands/metrics"
+ "github.com/apache/skywalking-cli/internal/commands/profile"
"github.com/apache/skywalking-cli/internal/commands/service"
"github.com/apache/skywalking-cli/internal/commands/trace"
"github.com/apache/skywalking-cli/internal/logger"
@@ -122,6 +123,7 @@ func main() {
install.Command,
event.Command,
logs.Command,
+ profile.Command,
}
app.Before = interceptor.BeforeChain([]cli.BeforeFunc{
diff --git a/internal/commands/profile/create.go b/internal/commands/profile/create.go
new file mode 100644
index 0000000..7993ba2
--- /dev/null
+++ b/internal/commands/profile/create.go
@@ -0,0 +1,106 @@
+// 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 profile
+
+import (
+ "fmt"
+
+ "github.com/apache/skywalking-cli/internal/logger"
+ "github.com/apache/skywalking-cli/pkg/display"
+ "github.com/apache/skywalking-cli/pkg/display/displayable"
+ "github.com/apache/skywalking-cli/pkg/graphql/metadata"
+ "github.com/apache/skywalking-cli/pkg/graphql/profile"
+
+ api "skywalking.apache.org/repo/goapi/query"
+
+ "github.com/urfave/cli"
+)
+
+var createCommand = cli.Command{
+ Name: "create",
+ Aliases: []string{"c"},
+ Usage: "create a new profile task",
+ ArgsUsage: "[parameters...]",
+ Flags: []cli.Flag{
+ cli.StringFlag{
+ Name: "service-id",
+ Usage: "<service-id> whose endpoints are to be profile.",
+ },
+ cli.StringFlag{
+ Name: "service-name",
+ Usage: "<service-name> whose endpoints are to be profile.",
+ },
+ cli.StringFlag{
+ Name: "endpoint",
+ Usage: "which endpoint should profile.",
+ },
+ cli.Int64Flag{
+ Name: "start-time",
+ Usage: "profile task start time(millisecond).",
+ },
+ cli.IntFlag{
+ Name: "duration",
+ Usage: "profile task continuous time(minute).",
+ },
+ cli.IntFlag{
+ Name: "min-duration-threshold",
+ Usage: "profiled endpoint must greater duration(millisecond).",
+ },
+ cli.IntFlag{
+ Name: "dump-period",
+ Usage: "profiled endpoint dump period(millisecond).",
+ },
+ cli.IntFlag{
+ Name: "max-sampling-count",
+ Usage: "profile task max sampling count.",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ serviceID := ctx.String("service-id")
+ if serviceID == "" {
+ serviceName := ctx.String("service-name")
+ if serviceName == "" {
+ return fmt.Errorf(`either flags "service-id" or "service-name" must be set`)
+ }
+ service, err := metadata.SearchService(ctx, serviceName)
+ if err != nil {
+ return err
+ }
+ serviceID = service.ID
+ }
+
+ startTime := ctx.Int64("start-time")
+ request := &api.ProfileTaskCreationRequest{
+ ServiceID: serviceID,
+ EndpointName: ctx.String("endpoint"),
+ StartTime: &startTime,
+ Duration: ctx.Int("duration"),
+ MinDurationThreshold: ctx.Int("min-duration-threshold"),
+ DumpPeriod: ctx.Int("dump-period"),
+ MaxSamplingCount: ctx.Int("max-sampling-count"),
+ }
+
+ task, err := profile.CreateTask(ctx, request)
+
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+
+ return display.Display(ctx, &displayable.Displayable{Data: task, Condition: request})
+ },
+}
diff --git a/internal/commands/profile/getProfileAnalyze.go b/internal/commands/profile/getProfileAnalyze.go
new file mode 100644
index 0000000..8847ad0
--- /dev/null
+++ b/internal/commands/profile/getProfileAnalyze.go
@@ -0,0 +1,78 @@
+// 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 profile
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/apache/skywalking-cli/internal/logger"
+ "github.com/apache/skywalking-cli/pkg/display"
+ "github.com/apache/skywalking-cli/pkg/display/displayable"
+ "github.com/apache/skywalking-cli/pkg/graphql/profile"
+
+ "github.com/urfave/cli"
+
+ api "skywalking.apache.org/repo/goapi/query"
+)
+
+var getProfiledAnalyzeCommand = cli.Command{
+ Name: "profiled-analyze",
+ Aliases: []string{"pa"},
+ Usage: "analyze profiled segment.",
+ ArgsUsage: "[parameters...]",
+ Flags: []cli.Flag{
+ cli.StringFlag{
+ Name: "segment-id",
+ Usage: "profiled segment id.",
+ },
+ cli.StringFlag{
+ Name: "time-ranges",
+ Usage: "need to analyze time ranges in the segment: start-end,start-end",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ segmentID := ctx.String("segment-id")
+
+ tagStr := ctx.String("time-ranges")
+ var timeRanges []*api.ProfileAnalyzeTimeRange = nil
+ if tagStr != "" {
+ tagArr := strings.Split(tagStr, ",")
+ for _, tag := range tagArr {
+ kv := strings.Split(tag, "-")
+ start, err := strconv.ParseInt(kv[0], 10, 64)
+ if err != nil {
+ return err
+ }
+ end, err := strconv.ParseInt(kv[1], 10, 64)
+ if err != nil {
+ return err
+ }
+ timeRanges = append(timeRanges, &api.ProfileAnalyzeTimeRange{Start: start, End: end})
+ }
+ }
+
+ analysis, err := profile.GetProfileAnalyze(ctx, segmentID, timeRanges)
+
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+
+ return display.Display(ctx, &displayable.Displayable{Data: analysis, Condition: segmentID})
+ },
+}
diff --git a/internal/commands/profile/getProfiledSegment.go b/internal/commands/profile/getProfiledSegment.go
new file mode 100644
index 0000000..5df747b
--- /dev/null
+++ b/internal/commands/profile/getProfiledSegment.go
@@ -0,0 +1,50 @@
+// 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 profile
+
+import (
+ "github.com/apache/skywalking-cli/internal/logger"
+ "github.com/apache/skywalking-cli/pkg/display"
+ "github.com/apache/skywalking-cli/pkg/display/displayable"
+ "github.com/apache/skywalking-cli/pkg/graphql/profile"
+
+ "github.com/urfave/cli"
+)
+
+var getProfiledSegmentCommand = cli.Command{
+ Name: "profiled-segment",
+ Aliases: []string{"ps"},
+ Usage: "query profile task segment list",
+ ArgsUsage: "[parameters...]",
+ Flags: []cli.Flag{
+ cli.StringFlag{
+ Name: "segment-id",
+ Usage: "profiled segment id.",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ segmentID := ctx.String("segment-id")
+ segment, err := profile.GetProfiledSegment(ctx, segmentID)
+
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+
+ return display.Display(ctx, &displayable.Displayable{Data: segment, Condition: segmentID})
+ },
+}
diff --git a/internal/commands/profile/getTaskList.go b/internal/commands/profile/getTaskList.go
new file mode 100644
index 0000000..67317f9
--- /dev/null
+++ b/internal/commands/profile/getTaskList.go
@@ -0,0 +1,75 @@
+// 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 profile
+
+import (
+ "fmt"
+
+ "github.com/apache/skywalking-cli/internal/logger"
+ "github.com/apache/skywalking-cli/pkg/display"
+ "github.com/apache/skywalking-cli/pkg/display/displayable"
+ "github.com/apache/skywalking-cli/pkg/graphql/metadata"
+ "github.com/apache/skywalking-cli/pkg/graphql/profile"
+
+ "github.com/urfave/cli"
+)
+
+var getTaskListCommand = cli.Command{
+ Name: "list",
+ Aliases: []string{"l"},
+ Usage: "query profile task list",
+ ArgsUsage: "[parameters...]",
+ Flags: []cli.Flag{
+ cli.StringFlag{
+ Name: "service-id",
+ Usage: "`<service id>` whose profile task are to be searched",
+ },
+ cli.StringFlag{
+ Name: "service-name",
+ Usage: "`<service name>` whose profile task are to be searched",
+ },
+ cli.StringFlag{
+ Name: "endpoint",
+ Usage: "`<endpoint>` whose profile task are to be searched",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ serviceID := ctx.String("service-id")
+ if serviceID == "" {
+ serviceName := ctx.String("service-name")
+ if serviceName == "" {
+ return fmt.Errorf(`either flags "service-id" or "service-name" must be set`)
+ }
+ service, err := metadata.SearchService(ctx, serviceName)
+ if err != nil {
+ return err
+ }
+ serviceID = service.ID
+ }
+
+ endpoint := ctx.String("endpoint")
+
+ task, err := profile.GetTaskList(ctx, serviceID, endpoint)
+
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+
+ return display.Display(ctx, &displayable.Displayable{Data: task, Condition: serviceID})
+ },
+}
diff --git a/internal/commands/profile/getTaskSegmentList.go b/internal/commands/profile/getTaskSegmentList.go
new file mode 100644
index 0000000..869241b
--- /dev/null
+++ b/internal/commands/profile/getTaskSegmentList.go
@@ -0,0 +1,50 @@
+// 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 profile
+
+import (
+ "github.com/apache/skywalking-cli/internal/logger"
+ "github.com/apache/skywalking-cli/pkg/display"
+ "github.com/apache/skywalking-cli/pkg/display/displayable"
+ "github.com/apache/skywalking-cli/pkg/graphql/profile"
+
+ "github.com/urfave/cli"
+)
+
+var getTaskSegmentListCommand = cli.Command{
+ Name: "segment-list",
+ Aliases: []string{"sl"},
+ Usage: "query profile task segment list",
+ ArgsUsage: "[parameters...]",
+ Flags: []cli.Flag{
+ cli.StringFlag{
+ Name: "task-id",
+ Usage: "`<task id>` whose profiled segment are to be searched",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ taskID := ctx.String("task-id")
+ segmentList, err := profile.GetTaskSegmentList(ctx, taskID)
+
+ if err != nil {
+ logger.Log.Fatalln(err)
+ }
+
+ return display.Display(ctx, &displayable.Displayable{Data: segmentList, Condition: taskID})
+ },
+}
diff --git a/internal/commands/profile/profile.go b/internal/commands/profile/profile.go
new file mode 100644
index 0000000..5f9136c
--- /dev/null
+++ b/internal/commands/profile/profile.go
@@ -0,0 +1,34 @@
+// 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 profile
+
+import (
+ "github.com/urfave/cli"
+)
+
+var Command = cli.Command{
+ Name: "profile",
+ Usage: "Profile related sub-command",
+ Subcommands: []cli.Command{
+ createCommand,
+ getTaskListCommand,
+ getTaskSegmentListCommand,
+ getProfiledSegmentCommand,
+ getProfiledAnalyzeCommand,
+ },
+}
diff --git a/pkg/graphql/profile/profile.go b/pkg/graphql/profile/profile.go
new file mode 100644
index 0000000..a086afd
--- /dev/null
+++ b/pkg/graphql/profile/profile.go
@@ -0,0 +1,86 @@
+// 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 profile
+
+import (
+ "github.com/apache/skywalking-cli/assets"
+ "github.com/apache/skywalking-cli/pkg/graphql/client"
+
+ "github.com/machinebox/graphql"
+
+ "github.com/urfave/cli"
+
+ api "skywalking.apache.org/repo/goapi/query"
+)
+
+func CreateTask(ctx *cli.Context, condition *api.ProfileTaskCreationRequest) (api.ProfileTaskCreationResult, error) {
+ var response map[string]api.ProfileTaskCreationResult
+
+ request := graphql.NewRequest(assets.Read("graphqls/profile/CreateTask.graphql"))
+ request.Var("condition", condition)
+
+ err := client.ExecuteQuery(ctx, request, &response)
+
+ return response["result"], err
+}
+
+func GetTaskList(ctx *cli.Context, serviceID, endpointName string) ([]*api.ProfileTask, error) {
+ var response map[string][]*api.ProfileTask
+
+ request := graphql.NewRequest(assets.Read("graphqls/profile/GetTaskList.graphql"))
+ request.Var("serviceId", serviceID)
+ request.Var("endpointName", endpointName)
+
+ err := client.ExecuteQuery(ctx, request, &response)
+
+ return response["result"], err
+}
+
+func GetTaskSegmentList(ctx *cli.Context, taskID string) ([]*api.BasicTrace, error) {
+ var response map[string][]*api.BasicTrace
+
+ request := graphql.NewRequest(assets.Read("graphqls/profile/GetTaskSegmentList.graphql"))
+ request.Var("taskId", taskID)
+
+ err := client.ExecuteQuery(ctx, request, &response)
+
+ return response["result"], err
+}
+
+func GetProfiledSegment(ctx *cli.Context, segmentID string) (api.ProfiledSegment, error) {
+ var response map[string]api.ProfiledSegment
+
+ request := graphql.NewRequest(assets.Read("graphqls/profile/GetProfiledSegment.graphql"))
+ request.Var("segmentId", segmentID)
+
+ err := client.ExecuteQuery(ctx, request, &response)
+
+ return response["result"], err
+}
+
+func GetProfileAnalyze(ctx *cli.Context, segmentID string, timeRanges []*api.ProfileAnalyzeTimeRange) (api.ProfileAnalyzation, error) {
+ var response map[string]api.ProfileAnalyzation
+
+ request := graphql.NewRequest(assets.Read("graphqls/profile/GetProfileAnalyze.graphql"))
+ request.Var("segmentId", segmentID)
+ request.Var("timeRanges", timeRanges)
+
+ err := client.ExecuteQuery(ctx, request, &response)
+
+ return response["result"], err
+}