Skip to content

Commit a6b8980

Browse files
authored
Merge pull request #11 from OpenAF/in=javathread
In=javathread
2 parents 4d77d00 + 3c10a3c commit a6b8980

File tree

5 files changed

+142
-2
lines changed

5 files changed

+142
-2
lines changed

data/completion.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ complete:
5050
opts:
5151
- name: javagcjoin=
5252
desc: If true it will return an array with each processed line.
53+
- name: in=javathread
54+
desc: A Java thread dump text file format or java pid
55+
opts:
56+
- name: javathreadpid=
57+
desc: The PID of the Java process to connect to -requires Java SDK-
5358
- name: in=jmx
5459
desc: Uses Java JMX to retrieve data from another Java process
5560
opts:

data/usage.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@
162162
"Input type": "javagc",
163163
"Description": "The Java GC log lines text format"
164164
},
165+
{
166+
"Input type": "javathread",
167+
"Description": "The Java Thread stack dump lines text format"
168+
},
165169
{
166170
"Input type": "jmx",
167171
"Description": "Uses Java JMX to retrieve data from another Java process"
@@ -703,6 +707,13 @@
703707
"Description": "If true it will return an array with each processed line."
704708
}
705709
],
710+
[
711+
{
712+
"Option": "javathreadpid",
713+
"Type": "Number",
714+
"Description": "Optional you can provider the local java process pid to try to get the thread stack trace (*)"
715+
}
716+
],
706717
[
707718
{
708719
"Option": "jmxpid",

src/docs/USAGE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ List of data input types that can be auto-detected (through the file extension o
7272
| ini | INI/Properties format |
7373
| javas | Tries to list java processes running locally (javainception=true to include itself) |
7474
| javagc | The Java GC log lines text format |
75+
| javathread | The Java Thread stack dump lines text format |
7576
| jmx | Uses Java JMX to retrieve data from another Java process |
7677
| json | A JSON format (auto-detected) |
7778
| jsonschema | Given a JSON schema format tries to generate sample data for it |
@@ -257,6 +258,20 @@ List of options to use when _in=javagc_:
257258

258259
---
259260

261+
### 🧾 JavaThread input options
262+
263+
List of options to use when _in=javathread_:
264+
265+
| Option | Type | Description |
266+
|--------|------|-------------|
267+
| javathreadpid | Number | Optional you can provider the local java process pid to try to get the thread stack trace (*) |
268+
269+
> (*) This requires running openaf/oafp with a Java JDK. Keep in mind that it will interrupt the target application to dump the necessary data.
270+
271+
> You can extract the input text data by executing ```kill -3 pid```
272+
273+
---
274+
260275
### 🧾 JMX input options
261276

262277
List of options to use when _in=jmx_:

src/include/inputFns.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,110 @@ var _inputFns = new Map([
508508
}
509509
_$o(_r, options)
510510
}],
511+
["javathread", (_res, options) => {
512+
var lines
513+
_showTmpMsg()
514+
if (isDef(params.javathreadpid)) {
515+
ow.loadJava()
516+
try {
517+
lines = ow.java.jcmd(params.javathreadpid, "Thread.print")
518+
lines = lines.split("\n").filter(l => l.startsWith("\""))
519+
} catch(e) {
520+
_exit(-1, "Error getting Java thread dump: " + e.message)
521+
}
522+
} else {
523+
if (isString(_res)) {
524+
lines = _res.split("\n")
525+
} else {
526+
_exit(-1, "javathreads is only supported with a raw input or javathreadpid=.")
527+
}
528+
}
529+
530+
// TODO: remove after OpenAF stable > 20240212
531+
var fnFromTimeAbbr = aStr => {
532+
_$(aStr, "aStr").isString().$_()
533+
534+
var ars = aStr.trim().match(/[\d\.]+[a-zA-Z]+/g), res = 0;
535+
if (!isArray(ars) || ars.length === 0) return parseFloat(aStr);
536+
for (var i in ars) {
537+
var ar = ars[i].match(/(\d+(?:\.\d+)?)\s*([a-zA-Z]+)/);
538+
if (isArray(ar) && ar.length > 0) {
539+
var v = Number(ar[1])
540+
var u = String(ar[2])
541+
542+
var _u = {
543+
"ms": 1,
544+
"s": 1000,
545+
"m": 60 * 1000,
546+
"h": 60 * 60 * 1000,
547+
"d": 24 * 60 * 60 * 1000,
548+
"w": 7 * 24 * 60 * 60 * 1000,
549+
"M": 30 * 24 * 60 * 60 * 1000,
550+
"y": 365 * 24 * 60 * 60 * 1000
551+
}
552+
if (isDef(_u[u])) {
553+
res += v * _u[u]
554+
} else {
555+
res += v
556+
}
557+
}
558+
}
559+
560+
return res
561+
}
562+
563+
var fnJavaTrans = (v, tA) => {
564+
if (v === null) return ""
565+
if (v === undefined) return ""
566+
if (isBoolean(v)) return Boolean(v)
567+
if (isNumber(v)) return Number(v)
568+
if (tA) return fnFromTimeAbbr(String(v))
569+
return String(v)
570+
}
571+
ow.loadFormat()
572+
573+
var _r = []
574+
lines.forEach(line => {
575+
if (line.startsWith("\"")) {
576+
var pt = java.util.regex.Pattern.compile("^\\\"(?<threadName>[^\"]+)\\\"" +
577+
"(?:\\s+#(?<threadId>\\d+))?" +
578+
"(?:\\s+\\[(?<threadIndex>\\d+)\\])?" +
579+
"(?:\\s+(?<daemon>daemon))?" +
580+
"(?:\\s+prio=(?<prio>\\d+))?" +
581+
"\\s+os_prio=(?<osPrio>\\d+)" +
582+
"(?:\\s+cpu=(?<cpu>[0-9.]+ms))?" +
583+
"(?:\\s+elapsed=(?<elapsed>[0-9.]+s))?" +
584+
"(?:\\s+tid=(?<tid>0x[a-fA-F0-9]+))?" +
585+
"(?:\\s+nid=(?<nid>0x[a-fA-F0-9]+|\\d+|\\S+))?" +
586+
"(?:\\s+(?<state>.*?))?" +
587+
"(?:\\s+\\[(?<address>[^\\]]+)\\])?" +
588+
"\\s*$")
589+
590+
var mt = pt.matcher(line)
591+
if (mt.find()) {
592+
var m = {
593+
threadGroup: fnJavaTrans(mt.group("threadName")).replace(/[^a-zA-z]?\d+$/, ""),
594+
threadName : fnJavaTrans(mt.group("threadName")),
595+
threadId : fnJavaTrans(mt.group("threadId")),
596+
threadIndex: fnJavaTrans(mt.group("threadIndex")),
597+
daemon : fnJavaTrans(mt.group("daemon")),
598+
prio : fnJavaTrans(mt.group("prio")),
599+
osPrio : fnJavaTrans(mt.group("osPrio")),
600+
cpu_ms : fnJavaTrans(mt.group("cpu"), true),
601+
elapsed_ms : fnJavaTrans(mt.group("elapsed"), true),
602+
tid : fnJavaTrans(mt.group("tid")),
603+
nid : fnJavaTrans(mt.group("nid")),
604+
state : fnJavaTrans(mt.group("state")),
605+
address : fnJavaTrans(mt.group("address"))
606+
}
607+
_r.push(m)
608+
} else {
609+
_r.push({ error: "Could not parse line: " + line })
610+
}
611+
}
612+
})
613+
_$o(_r, options)
614+
}],
511615
["javagc", (_res, options) => {
512616
if (!isBoolean(params.javagcjoin)) params.javagcjoin = toBoolean(_$(params.javagcjoin, "javagcjoin").isString().default(__))
513617

src/include/transformFns.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,19 @@ var _transformFns = {
196196
},
197197
"correcttypes" : _r => {
198198
if (toBoolean(params.correcttypes) && isObject(_r)) {
199+
ow.loadFormat()
199200
traverse(_r, (aK, aV, aP, aO) => {
200201
switch(descType(aV)) {
201202
case "number": if (isString(aV)) aO[aK] = Number(aV); break
202203
case "string":
203204
// String boolean
204205
if (aV.trim().toLowerCase() == "true" || aV.trim().toLowerCase() == "false") { aO[aK] = toBoolean(aV); break }
205206
// String ISO date
206-
if (aV.trim().match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/)) { aO[aK] = new Date(aV); break }
207+
if (isDef(ow.format.fromISODate)) {
208+
if (aV.trim().match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\d+Z$/)) { aO[aK] = ow.format.fromISODate(aV); break }
209+
} else {
210+
if (aV.trim().match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/)) { aO[aK] = new Date(aV); break }
211+
}
207212
// String date
208213
if (aV.trim().match(/^\d{4}-\d{2}-\d{2}$/)) { aO[aK] = new Date(aV); break }
209214
// String time with seconds
@@ -557,7 +562,7 @@ var _transformFns = {
557562
let _lst = params.field2date.split(",").map(r => r.trim())
558563
traverse(_r, (aK, aV, aP, aO) => {
559564
if (_lst.indexOf(aP.length > 0 && !aP.startsWith("[") ? aP.substring(1) + "." + aK : aK) >= 0 && isNumber(aV) && aV > 0) {
560-
try { aO[aK] = new Date(aV) } catch(e) {}
565+
try { aO[aK] = ow.format.fromISODate(aV) } catch(e) {}
561566
}
562567
})
563568
return _r

0 commit comments

Comments
 (0)