Skip to content

Commit cf49a86

Browse files
committed
fix(common.jolokia2): Add Jolokia 2.x compatibility for proxy target tag
Jolokia 2.x changed the response format for proxy requests. The target URL is now returned under `request.options.target` instead of `request.target` (Jolokia 1.x format). This change adds support for both formats by checking both locations when extracting the target URL for the `jolokia_agent_url` tag. Without this fix, metrics from jolokia2_proxy plugin using Jolokia 2.x are missing the `jolokia_agent_url` tag, making it impossible to distinguish metrics from different proxy targets.
1 parent b89f119 commit cf49a86

File tree

2 files changed

+204
-4
lines changed

2 files changed

+204
-4
lines changed

plugins/common/jolokia2/client.go

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,16 @@ type jolokiaTarget struct {
7777
Password string `json:"password,omitempty"`
7878
}
7979

80-
// Jolokia JSON response object. Example: {
80+
// jolokiaOptions represents the options field in Jolokia 2.x responses.
81+
// In Jolokia 2.x, the target is returned under request.options.target
82+
// instead of request.target (Jolokia 1.x format).
83+
type jolokiaOptions struct {
84+
Target *jolokiaTarget `json:"target,omitempty"`
85+
}
86+
87+
// Jolokia JSON response object. Example for Jolokia 1.x:
88+
//
89+
// {
8190
// "request": {
8291
// "type": "read"
8392
// "mbean": "java.lang:type=Runtime",
@@ -90,10 +99,35 @@ type jolokiaTarget struct {
9099
// "timestamp": 1488059309,
91100
// "status": 200
92101
// }
102+
//
103+
// Example for Jolokia 2.x:
104+
//
105+
// {
106+
// "request": {
107+
// "type": "read"
108+
// "mbean": "java.lang:type=Runtime",
109+
// "attribute": "Uptime",
110+
// "options": {
111+
// "target": {
112+
// "url": "service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi"
113+
// }
114+
// }
115+
// },
116+
// "value": 1214083,
117+
// "timestamp": 1488059309,
118+
// "status": 200
119+
// }
93120
type jolokiaResponse struct {
94-
Request jolokiaRequest `json:"request"`
95-
Value interface{} `json:"value"`
96-
Status int `json:"status"`
121+
Request jolokiaResponseRequest `json:"request"`
122+
Value interface{} `json:"value"`
123+
Status int `json:"status"`
124+
}
125+
126+
// jolokiaResponseRequest is the request object echoed back in a Jolokia response.
127+
// It extends jolokiaRequest with the Options field for Jolokia 2.x compatibility.
128+
type jolokiaResponseRequest struct {
129+
jolokiaRequest
130+
Options *jolokiaOptions `json:"options,omitempty"`
97131
}
98132

99133
func NewClient(address string, config *ClientConfig) (*Client, error) {
@@ -244,9 +278,14 @@ func makeReadResponses(jresponses []jolokiaResponse) []ReadResponse {
244278
RequestAttributes: rrequest.Attributes,
245279
RequestPath: rrequest.Path,
246280
}
281+
// Check for target in Jolokia 1.x location (request.target)
247282
if jtarget := jr.Request.Target; jtarget != nil {
248283
rresponse.RequestTarget = jtarget.URL
249284
}
285+
// Check for target in Jolokia 2.x location (request.options.target)
286+
if rresponse.RequestTarget == "" && jr.Request.Options != nil && jr.Request.Options.Target != nil {
287+
rresponse.RequestTarget = jr.Request.Options.Target.URL
288+
}
250289

251290
rresponses = append(rresponses, rresponse)
252291
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package jolokia2
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestMakeReadResponses_Jolokia1xTarget(t *testing.T) {
10+
// Jolokia 1.x returns target directly in request.target
11+
jresponses := []jolokiaResponse{
12+
{
13+
Request: jolokiaResponseRequest{
14+
jolokiaRequest: jolokiaRequest{
15+
Type: "read",
16+
Mbean: "java.lang:type=Runtime",
17+
Attribute: "Uptime",
18+
Target: &jolokiaTarget{
19+
URL: "service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi",
20+
},
21+
},
22+
},
23+
Value: 1214083,
24+
Status: 200,
25+
},
26+
}
27+
28+
responses := makeReadResponses(jresponses)
29+
30+
require.Len(t, responses, 1)
31+
require.Equal(t, "service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi", responses[0].RequestTarget)
32+
require.Equal(t, "java.lang:type=Runtime", responses[0].RequestMbean)
33+
require.Equal(t, 200, responses[0].Status)
34+
}
35+
36+
func TestMakeReadResponses_Jolokia2xTarget(t *testing.T) {
37+
// Jolokia 2.x returns target in request.options.target
38+
jresponses := []jolokiaResponse{
39+
{
40+
Request: jolokiaResponseRequest{
41+
jolokiaRequest: jolokiaRequest{
42+
Type: "read",
43+
Mbean: "java.lang:type=Runtime",
44+
Attribute: "Uptime",
45+
},
46+
Options: &jolokiaOptions{
47+
Target: &jolokiaTarget{
48+
URL: "service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi",
49+
},
50+
},
51+
},
52+
Value: 1214083,
53+
Status: 200,
54+
},
55+
}
56+
57+
responses := makeReadResponses(jresponses)
58+
59+
require.Len(t, responses, 1)
60+
require.Equal(t, "service:jmx:rmi:///jndi/rmi://target:9010/jmxrmi", responses[0].RequestTarget)
61+
require.Equal(t, "java.lang:type=Runtime", responses[0].RequestMbean)
62+
require.Equal(t, 200, responses[0].Status)
63+
}
64+
65+
func TestMakeReadResponses_NoTarget(t *testing.T) {
66+
// No target (direct agent connection, not proxy)
67+
jresponses := []jolokiaResponse{
68+
{
69+
Request: jolokiaResponseRequest{
70+
jolokiaRequest: jolokiaRequest{
71+
Type: "read",
72+
Mbean: "java.lang:type=Runtime",
73+
Attribute: "Uptime",
74+
},
75+
},
76+
Value: 1214083,
77+
Status: 200,
78+
},
79+
}
80+
81+
responses := makeReadResponses(jresponses)
82+
83+
require.Len(t, responses, 1)
84+
require.Equal(t, "", responses[0].RequestTarget)
85+
require.Equal(t, "java.lang:type=Runtime", responses[0].RequestMbean)
86+
}
87+
88+
func TestMakeReadResponses_Jolokia1xTakesPrecedence(t *testing.T) {
89+
// If both locations have a target, Jolokia 1.x location takes precedence
90+
jresponses := []jolokiaResponse{
91+
{
92+
Request: jolokiaResponseRequest{
93+
jolokiaRequest: jolokiaRequest{
94+
Type: "read",
95+
Mbean: "java.lang:type=Runtime",
96+
Attribute: "Uptime",
97+
Target: &jolokiaTarget{
98+
URL: "service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi",
99+
},
100+
},
101+
Options: &jolokiaOptions{
102+
Target: &jolokiaTarget{
103+
URL: "service:jmx:rmi:///jndi/rmi://target2:9010/jmxrmi",
104+
},
105+
},
106+
},
107+
Value: 1214083,
108+
Status: 200,
109+
},
110+
}
111+
112+
responses := makeReadResponses(jresponses)
113+
114+
require.Len(t, responses, 1)
115+
// Jolokia 1.x location (request.target) takes precedence
116+
require.Equal(t, "service:jmx:rmi:///jndi/rmi://target1:9010/jmxrmi", responses[0].RequestTarget)
117+
}
118+
119+
func TestMakeReadResponses_MultipleTargets(t *testing.T) {
120+
// Multiple responses with different targets (Jolokia 2.x format)
121+
jresponses := []jolokiaResponse{
122+
{
123+
Request: jolokiaResponseRequest{
124+
jolokiaRequest: jolokiaRequest{
125+
Type: "read",
126+
Mbean: "java.lang:type=Runtime",
127+
Attribute: "Uptime",
128+
},
129+
Options: &jolokiaOptions{
130+
Target: &jolokiaTarget{
131+
URL: "service:jmx:rmi:///jndi/rmi://host1:9010/jmxrmi",
132+
},
133+
},
134+
},
135+
Value: 1000,
136+
Status: 200,
137+
},
138+
{
139+
Request: jolokiaResponseRequest{
140+
jolokiaRequest: jolokiaRequest{
141+
Type: "read",
142+
Mbean: "java.lang:type=Runtime",
143+
Attribute: "Uptime",
144+
},
145+
Options: &jolokiaOptions{
146+
Target: &jolokiaTarget{
147+
URL: "service:jmx:rmi:///jndi/rmi://host2:9010/jmxrmi",
148+
},
149+
},
150+
},
151+
Value: 2000,
152+
Status: 200,
153+
},
154+
}
155+
156+
responses := makeReadResponses(jresponses)
157+
158+
require.Len(t, responses, 2)
159+
require.Equal(t, "service:jmx:rmi:///jndi/rmi://host1:9010/jmxrmi", responses[0].RequestTarget)
160+
require.Equal(t, "service:jmx:rmi:///jndi/rmi://host2:9010/jmxrmi", responses[1].RequestTarget)
161+
}

0 commit comments

Comments
 (0)