Skip to content

Commit 143875b

Browse files
committed
Bug Fix
issue with true result in case command was ignored, closing file to prevent potential blocking on io operation, true transmitted status if dmesg capturing skipped, issue with a specified thread dump file, closing javacore file to prevent potential blocking on io operation
1 parent 3bbe702 commit 143875b

File tree

13 files changed

+121
-109
lines changed

13 files changed

+121
-109
lines changed

README.md

Lines changed: 78 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,82 @@
1-
# yc-data-script
2-
3-
![img](/docs/images/360-degree.png)
4-
5-
## What does the yc-data-script do?
6-
7-
yc-data-script is a simple Golang script that captures 16 different artifacts from your application in a **pristine** manner. These artifacts will be highly useful to troubleshoot performance problems. Below is the list of artifacts captured:
8-
9-
1. Garbage collection log
10-
2. Thread dump
11-
3. Heap dump
12-
4. Heap substitute
13-
5. top
14-
6. ps
15-
7. top -H
16-
8. Disk usage
17-
9. dmesg
18-
10. netstat
19-
11. ping
20-
12. vmstat
21-
13. iostat
22-
14. Kernel parameters
23-
15. Application Log
24-
16. Metadata
25-
26-
## How to run the yc-data-script?
27-
28-
1. Download latest yc-data-script from [this](https://tier1app.com/dist/ycrash/yc-agent-latest.zip) location
29-
2. Unzip the downloaded ```yc-agent-latest.zip``` file. (Say you are unzipping in '/opt/workspace/yc-agent-latest' folder)
30-
3. In the unzipped folder you will find yc-data-script by operating system:
31-
32-
a) ```linux/yc``` - If you are running on Unix/Linux, then use this script.
33-
34-
b) ```windows/yc.exe``` - If you are running on Windows, then use this script.
35-
36-
c) ```mac/yc``` - If you are running on MAC, then use this script.
1+
### Usage of argument options:
2+
```bash
3+
Usage of yc:
4+
-a string
5+
The APP Name of the target
6+
-c string
7+
The config file path to load
8+
-cmd value
9+
The command to be executed, should be paired with '-urlParams' together
10+
-d Delete logs folder created during analyse, default is false
11+
-gcPath string
12+
The gc log file to be uploaded while it exists
13+
-hd
14+
Capture heap dump, default is false
15+
-hdPath string
16+
The heap dump file to be uploaded while it exists
17+
-j string
18+
The java home path to be used. Default will try to use os env 'JAVA_HOME' if 'JAVA_HOME' is not empty, for example: /usr/lib/jvm/java-8-openjdk-amd64
19+
-k string
20+
The API Key that will be used to make API requests, for example: tier1app@12312-12233-1442134-112
21+
-p int
22+
The process Id of the target, for example: 3121
23+
-s string
24+
The server url that will be used to upload data, for example: https://ycrash.companyname.com
25+
-tdPath string
26+
The thread dump file to be uploaded while it exists
27+
-urlParams value
28+
The params to be added at the end of upload request url, should be paired with '-cmd' together
29+
-version
30+
Show the version of this program
3731

3832
```
39-
./yc -j {JAVA_HOME} -onlyCapture -p {PID} -hd
33+
### Example of config file:
34+
```yaml
35+
version: "1"
36+
options:
37+
a: name
38+
d: false
39+
hd: false
40+
j: /usr/lib/jvm/java-8-openjdk-amd64
41+
k: buggycompany@e094aasdsa-c3eb-4c9a-8254-f0dd107245cc
42+
p: 3121
43+
s: https://gceasy.io
44+
gcPath: /var/log/gc.log
45+
hdPath: /var/log/heapdump.log
46+
tdPath: /var/log/threaddump.log
47+
cmds:
48+
- urlParams: dt=vmstat
49+
cmd: vmstat 1 1
4050
```
41-
Where,
42-
43-
**JAVA_HOME** is the home directory where JDK is installed
44-
45-
**PID** is the target JVM's process ID
46-
47-
**Example:**
48-
49-
```
50-
./yc -j /usr/java/jdk1.8.0_141 -onlyCapture -p 15326 -hd
51-
```
52-
53-
When you pass the above arguments, yc-data-script will capture all the application level and system level artifacts/logs from the server from the target JVM & host for analysis. Captured artifacts will be compressed into a zip file and stored in the current directory where the above command was executed. The zip file will have the name in the format: 'yc-YYYY-MM-DDTHH-mm-ss.zip'.
54-
55-
**Example:** 'yc-2021-03-06T14-02-42.zip'.
56-
57-
## How to analyze the artifacts generated by the yc-data-script?
58-
59-
You can analyze the artifacts captured by yc-data-script either manually or through [yCrash server](https://ycrash.io/). yCrash server analyzes all the captured data and generates a root cause analysis report instantly. You can use the [Bundle upload](https://docs.ycrash.io/ycrash-features/bundle-upload.html#step-1-go-to-upload-incident-form) feature in the yCrash server to analyze the captured 360-degree data.
60-
61-
### Advanced launch modes
62-
63-
You can launch yc-data-script in following [3 different modes](https://docs.ycrash.io/ycrash-agent/launch-modes.html#launch-modes):
64-
65-
1. **On-demand Mode:** In this mode you can directly transmit 360-degree artifacts from your server to yCrash server for analysis.
66-
2. **API Mode:** In this mode you can integrate yc-data-script with your current monitoring tools such as AppDynamics, New Relic, Dynatrace, …
67-
3. **M3 (Micro-metrics Monitoring) mode:** In this mode, yc-data-script proactively detect performance outages much earlier before it surfaces
68-
69-
## How to build the yc-data-script?
70-
71-
Please refer to any one of the following links if you want to build the yc-data-script in that corresponding operating system:
7251
73-
1. Build yc-data-script in [Windows](/docs/Build%20yc%20agent%20in%20Windows.pdf)
74-
2. Build yc-data-script in [Linux](/docs/build-yc-agent-linux.md)
75-
3. Build yc-data-script in [MacOS](/docs/build-yc-agent-macos.md)
52+
The config file is using yaml format. The name of the option keys is same as the name of argument options.
53+
54+
'-s': the server url that will be used to upload data.
55+
'-k': the API key that will be used to make API requests.
56+
'-j': the java home path to be used. Default will try to use os env 'JAVA_HOME' if 'JAVA_HOME' is not empty.
57+
'-a': the app name of the target.
58+
'-p': the pid of the target.
59+
'-d': delete logs folder created during analyse, default is false.
60+
'-hd': capture heap dump, default is false.
61+
'-gcPath': the gc log file to be uploaded while it exists, otherwise it will captures one if failed to get the path from '-Xlog:gc' or '-Xloggc'.
62+
'-hdPath': the heap dump file to be uploaded while it exists.
63+
'-tdPath': the thread dump file to be uploaded while it exists, otherwise it will captures one.
64+
65+
Only for argument options:
66+
'-version' show the version of this program.
67+
'-c': the config file path to load.
68+
69+
### Example to capture info from target with pid 3121:
70+
71+
`yc -p 3121 -s https://gceasy.io -k testCompany@e094a34e-c3eb-4c9a-8254-f0dd107245cc -j /usr/lib/jvm/java-11-openjdk-amd64 -c ./config.yaml`
72+
73+
### Example to execute custom commands after the capturing:
74+
75+
- By arguments. One '-urlParams' should be paired with one '-cmd'.
76+
`yc ... -urlParams dt=vmstat -cmd "vmstat 1 1" -urlParams dt=pidstat -cmd "pidstat 1 1" ...`
77+
- By config file.
78+
```yaml
79+
cmds:
80+
- urlParams: dt=vmstat
81+
cmd: vmstat 1 1
82+
```

capture/custom.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (c *Custom) Run() (result Result, err error) {
2626
}
2727
if c.Cmd.IsSkipped() {
2828
result.Msg = "skipped capturing custom"
29-
result.Ok = true
29+
result.Ok = false
3030
return
3131
}
3232
c.Cmd.Wait()

capture/gc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ func (t *GC) Run() (result Result, err error) {
7777
}
7878
}
7979

80+
if gcFile != nil {
81+
defer func() {
82+
_ = gcFile.Close()
83+
}()
84+
}
85+
8086
result.Msg, result.Ok = shell.PostData(t.Endpoint(), "gc", gcFile)
8187
absGCPath, err := filepath.Abs(t.GCPath)
8288
if err != nil {

capture/jstack.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,11 @@ func (t *JStack) Run() (result Result, err error) {
9292
return
9393
}
9494

95-
defer func() {
96-
e := jstackFile.Sync()
97-
if e != nil {
98-
logger.Log("failed to sync file %s", e)
99-
}
100-
e = jstackFile.Close()
101-
if e != nil {
102-
logger.Log("failed to close file %s", e)
103-
}
104-
}()
105-
10695
_, e := jstackFile.WriteString("\nFull thread dump\n")
10796
if e != nil {
10897
logger.Log("failed to write file %s", e)
10998
e1 <- e
99+
_ = jstackFile.Close()
110100
return
111101
}
112102
_, err = (&JStackF{
@@ -117,13 +107,18 @@ func (t *JStack) Run() (result Result, err error) {
117107
if err != nil {
118108
logger.Log("failed to collect dump using jstack -F : %v", err)
119109
e1 <- err
110+
_ = jstackFile.Close()
120111
return
121112
}
122113
}
123114

124-
e := jstackFile.Sync()
125-
if e != nil {
126-
logger.Log("failed to sync file %v", e)
115+
var e error
116+
if jstackFile != nil {
117+
e := jstackFile.Sync()
118+
if e != nil {
119+
logger.Log("failed to sync file %v", e)
120+
}
121+
_ = jstackFile.Close()
127122
}
128123

129124
// necessary to send something into channel to prevent blocking inside waiting loop

capture/kernel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func (k *Kernel) Run() (result Result, err error) {
2121
}
2222
if k.Cmd.IsSkipped() {
2323
result.Msg = "skipped capturing Kernel"
24-
result.Ok = true
24+
result.Ok = false
2525
return
2626
}
2727
k.Cmd.Wait()

capture/ping.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (c *Ping) Run() (result Result, err error) {
2222
}
2323
if c.Cmd.IsSkipped() {
2424
result.Msg = "skipped capturing Ping"
25-
result.Ok = true
25+
result.Ok = false
2626
return
2727
}
2828
c.Cmd.Wait()

capture/thread.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,28 @@ func (t *ThreadDump) Run() (result Result, err error) {
2727
if err != nil {
2828
logger.Log("failed to open tdPath(%s), err: %s", t.TdPath, err.Error())
2929
} else {
30-
defer tdf.Close()
30+
defer func() {
31+
_ = tdf.Close()
32+
}()
3133
td, err = os.Create(tdOut)
3234
if err != nil {
35+
result.Msg = err.Error()
3336
return
3437
}
35-
defer td.Close()
38+
defer func() {
39+
_ = td.Close()
40+
}()
3641
_, err = io.Copy(td, tdf)
3742
if err != nil {
43+
result.Msg = err.Error()
3844
return
3945
}
4046
_, err = td.Seek(0, 0)
4147
if err != nil {
48+
result.Msg = err.Error()
4249
return
4350
}
4451
}
45-
return
4652
}
4753
if t.Pid > 0 && td == nil {
4854
if !shell.IsProcessExists(t.Pid) {
@@ -71,7 +77,9 @@ func (t *ThreadDump) Run() (result Result, err error) {
7177
if err != nil {
7278
return
7379
}
74-
defer td.Close()
80+
defer func() {
81+
_ = td.Close()
82+
}()
7583
}
7684
result.Msg, result.Ok = shell.PostData(t.Endpoint(), "td", td)
7785
return

capture/top.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type Top struct {
2121
func (t *Top) Run() (result Result, err error) {
2222
if len(shell.Top) < 1 {
2323
result.Msg = "skipped capturing TopH"
24-
result.Ok = true
24+
result.Ok = false
2525
return
2626
}
2727
file, err := os.Create("top.out")
@@ -40,7 +40,7 @@ func (t *Top) Run() (result Result, err error) {
4040
}
4141
if t.Cmd.IsSkipped() {
4242
result.Msg = "skipped capturing Top"
43-
result.Ok = true
43+
result.Ok = false
4444
return
4545
}
4646
err = t.Cmd.Wait()
@@ -69,7 +69,7 @@ func (t *Top) Run() (result Result, err error) {
6969
logger.Log("trying %q, cause %q exit code != 0, read err %s %v", t.Cmd.String(), oCmd, output, rErr)
7070
if t.Cmd.IsSkipped() {
7171
result.Msg = "skipped capturing Top"
72-
result.Ok = true
72+
result.Ok = false
7373
return
7474
}
7575
err = t.Cmd.Wait()
@@ -94,7 +94,7 @@ type TopH struct {
9494
func (t *TopH) Run() (result Result, err error) {
9595
if len(shell.TopH) < 1 {
9696
result.Msg = "skipped capturing TopH"
97-
result.Ok = true
97+
result.Ok = false
9898
return
9999
}
100100
if !shell.IsProcessExists(t.Pid) {
@@ -127,7 +127,7 @@ func (t *TopH) Run() (result Result, err error) {
127127
}
128128
if t.Cmd.IsSkipped() {
129129
result.Msg = "skipped capturing TopH"
130-
result.Ok = true
130+
result.Ok = false
131131
return
132132
}
133133
err = t.Cmd.Wait()
@@ -156,7 +156,7 @@ func (t *TopH) Run() (result Result, err error) {
156156
logger.Log("trying %q, cause %q exit code != 0, read err %s %v", t.Cmd.String(), oCmd, output, rErr)
157157
if t.Cmd.IsSkipped() {
158158
result.Msg = "skipped capturing TopH"
159-
result.Ok = true
159+
result.Ok = false
160160
return
161161
}
162162
err = t.Cmd.Wait()
@@ -174,7 +174,7 @@ type Top4M3 struct {
174174
func (t *Top4M3) Run() (result Result, err error) {
175175
if len(shell.Top4M3) < 1 {
176176
result.Msg = "skipped capturing TopH"
177-
result.Ok = true
177+
result.Ok = false
178178
return
179179
}
180180
top, err := os.Create("top4m3.out")
@@ -195,7 +195,7 @@ func (t *Top4M3) Run() (result Result, err error) {
195195
}
196196
if t.Cmd.IsSkipped() {
197197
result.Msg = "skipped capturing Top"
198-
result.Ok = true
198+
result.Ok = false
199199
return
200200
}
201201
err = t.Cmd.Wait()

capture/vmstat.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (t *VMStat) Run() (result Result, err error) {
3131
t.Cmd, err = shell.CommandStartInBackgroundToWriter(file, cmd)
3232
if t.Cmd.IsSkipped() {
3333
result.Msg = "skipped capturing VMStat"
34-
result.Ok = true
34+
result.Ok = false
3535
return
3636
}
3737
if err != nil {

const.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
// Generic Properties
1313
// ------------------------------------------------------------------------------
1414
var (
15-
SCRIPT_VERSION = "yc_agent_1.0.6"
15+
SCRIPT_VERSION = "yc_agent_1.0.11"
1616
SCRIPT_SPAN = 120 // How long the whole script should take. Default=240
1717
JAVACORE_INTERVAL = 30 // How often javacores should be taken. Default=30
1818
TOP_INTERVAL = 60 // How often top data should be taken. Default=60

0 commit comments

Comments
 (0)