-
Notifications
You must be signed in to change notification settings - Fork 44
/
java_show_classpath.pl
executable file
·165 lines (150 loc) · 5.15 KB
/
java_show_classpath.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/usr/bin/perl -T
#
# Author: Hari Sekhon
# Date: 2013-02-11 11:50:00 +0000 (Mon, 11 Feb 2013)
#
# https://github.com/HariSekhon/DevOps-Perl-tools
#
# License: see accompanying Hari Sekhon LICENSE file
#
# If you're using my code you're welcome to connect with me on LinkedIn
# and optionally send me feedback to help improve or steer this or other code I publish
#
# https://www.linkedin.com/in/HariSekhon
#
$DESCRIPTION = "Prints all the command line classpaths of Java processes
Optionally filtering Java processes by a given regex
Credit to Clint Heath & Linden Hillenbrand @ Cloudera for giving me this idea";
$VERSION = 0.5;
use strict;
use warnings;
BEGIN {
use File::Basename;
use lib dirname(__FILE__) . "/lib";
}
use HariSekhonUtils qw/:DEFAULT :regex/;
$ENV{'PATH'} = '/bin:/usr/bin:/usr/java/default/bin:/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands';
my $command_regex = "";
my $stdin = 0;
%options = (
"C|command_regex=s" => [ \$command_regex, "Regex of classname for JPS or command for 'ps -ef' or 'ps aux' if piping in 'ps -ef' or 'ps aux' input. Default \"\" shows all java processes" ],
"s|stdin" => [ \$stdin, "Read process one per line from stdin (should be in format of 'jps', 'ps -ef', or 'ps aux' command outputs)" ],
);
get_options();
if (@ARGV == 0){
} elsif (@ARGV == 1 and $command_regex eq ""){
$command_regex = $ARGV[0];
} else {
usage;
}
if(defined($command_regex)){
if(! eval { qr/$command_regex/ }){
die "invalid command regex supplied: $command_regex\n";
}
}
# XXX: this is truncated to 4096 chars which for programs with very long cli classpaths is a hard coded kernel problem
sub show_cli_classpath($){
my $cmd = shift;
$cmd =~ /\bjava\b/ or return;
( my $args = $cmd ) =~ s/.*?java\s+//;
#$cmd =~ s/\s-(?:cp|classpath)(?:\s+|=)([^\s+]+)(?:\s|$)/ <CLASSPATHS> /;
print "\ncommand: $cmd\n\n";
my $count = 0;
if($args =~ /\s-(?:cp|classpath)(?:\s+|=)([^\s+]+)(?:\s|$)/i){
foreach(split(/:/, $1)){
next if /^\s*$/;
print "classpath: $_\n";
$count++;
}
}
print "\n" if $count;
plural $count;
print "$count classpath$plural found\n\n";
}
# the blank case is an embedded JVM with no main classname, ie Impalad's embedded JVM in C++ for HDFS calls
my $jps_regex = qr/^(\d+)\s+(\w*)$/;
sub show_jinfo_classpath($){
my $cmd = shift;
my $pid;
if($cmd =~ $jps_regex){
$pid = $1;
return if $2 eq "Jps";
unless($2){
$cmd .= "<embedded JVM no classname from JPS output>";
}
debug "JPS input detected";
print "JPS: $cmd\n";
print "command: " . `ps -f -p $pid | tail -n +2 | sed 's/^[[:space:]]*//'` . "\n\n";
} else {
unless($cmd =~ /\bjava\b/){
vlog2 "skipping $cmd since it doesn't match /\\bjava\\b/";
return;
}
#$cmd =~ s/\s-(?:cp|classpath)(?:\s+|=)([^\s+]+)(?:\s|$)/ <CLASSPATHS> /;
print "\ncommand: $cmd\n\n";
# support ps -ef and ps aux type inputs for convenience
if($cmd =~ /^\s*\w+\s+(\d+)\s+\d+(?:\.\d+)?\s+\d+(?:\.\d+)?/){
debug "ps -ef input detected";
} elsif($cmd =~ /^\s*(\d+)\s+\w+\s+(?:$filename_regex\/)?java.+$/){
debug "ps aux input detected";
} else {
die "Invalid input to show_jinfo_classpath, expecting '<pid> <classname>' or '<pid> <user> <cmd>' or 'ps -ef' or 'ps aux' input\n";
}
$pid = $1;
}
my @output = cmd("jinfo $pid");
my $found_classpath = 0;
foreach(@output){
# breaks on this content:
#
# /Users/hari/Library/Application Support/JetBrains/IdeaIC2023.3/plugins/sonarlint-intellij/sloop/lib/error_prone_annotations-2.18.0.jar
#
#if(/error/i){
# die "jinfo error attaching to process id $pid\n$_\n";
#}
/^java.class.path\s*=\s*/ or next;
s/^java.class.path\s*=\s*//;
my $count = 0;
foreach(split(/\\?:/, $_)){
next if /^\s*$/;
print "classpath: $_\n";
$count++;
}
print "\n" if $count;
#print "\n" . "="x80 . "\n";
plural $count;
print "$count classpath$plural found\n\n";
$found_classpath = 1;
last;
}
$found_classpath or die "Failed to find java classpath in output from jinfo!\n";
print "="x80 . "\n";
}
my $fh;
if($stdin){
$fh = *STDIN;
} else {
unless(open $fh, "jps |"){
warn "\nWARNING: jps failed, perhaps not in \$PATH? (\$PATH = $ENV{PATH})\n";
warn "\nWARNING: Falling back to ps command, may be less accurate\n\n";
open $fh, "ps -e -o pid,user,command |";
}
}
while(<$fh>){
chomp;
debug "input: $_";
if($_ =~ $jps_regex){
debug "JPS process detected";
if($command_regex){
if($2 =~ /$command_regex/io){
show_jinfo_classpath($_);
}
} else {
show_jinfo_classpath($_);
}
} elsif(/\bjava\s.*$command_regex/io){
debug "Java command detected";
#show_cli_classpath($_);
show_jinfo_classpath($_);
}
}