You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Jerry Malcolm <te...@malcolms.com> on 2019/12/05 18:42:13 UTC

JMX 101 Question

I'm trying to add some code to monitor my jdbc data connection pool.  
Each time a connection is requested, I have some jmx code that logs 
values from the datasource mbean.  I haven't done much jmx coding.  So 
consider me a rookie on this topic.  I found some code on the web that 
does pretty much what I need. The relevant part of the code:

           MBeanServer server = ManagementFactory.getPlatformMBeanServer();
           Set<ObjectName> objectNames = server.queryNames(null, null);
           for (ObjectName name : objectNames) {
               MBeanInfo info = server.getMBeanInfo(name);
               if (info.getClassName().equals( 
"org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool"))  {
                   for (MBeanAttributeInfo mf : info.getAttributes()) {

This code works.  The problem is that I have a bunch of virtual hosts 
running on the same instance of TC.  So I get a bunch of matching 
mbeans, apparently one for each virtual host / resource defined.

Is there any way to identify which mbean is for the datasource I 
currently care about?  I was hoping there would be an attribute with the 
datasource name or the database name or even just some way to add a 
unique identifier when I create it.  But I don't see anything.  I've 
resorted to having maxTotal set to incrementally different values in all 
of my resource statements just so I can identify the datasource I'm 
looking at in the logs.  But that's a hack.

Is there a better way to uniquely identify datasource mbeans in jmx?

Thx



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: JMX 101 Question

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Jerry,

On 12/6/19 01:58, Jerry Malcolm wrote:
> Hi Chris,
> 
> See below
> 
> On 12/5/2019 1:07 PM, Christopher Schultz wrote: Jerry,
> 
> On 12/5/19 13:42, Jerry Malcolm wrote:
>>>> I'm trying to add some code to monitor my jdbc data
>>>> connection pool.
> Before you do that, is this a pool that is application-managed? If 
> Tomcat is managing the connection pool, then none of this is 
> necessary. If it's application-managed, I'm curious as to why you
> are doing that rather than having Tomcat manage it for you. Would
> you mind explaining if that's the case?
> 
>> It's tomcat managed.
> 
>> | >> none of this is necessary
> 
>> Are you telling me that it's unnecessary for me to know how many 
>> connections are currently in use in my connection pool??

Not at all; it's perfectly reasonable to want to know the current stat
of affairs. I'm telling you that Tomcat already has a JMX bean that
can tell you what you want to know. So you don't have to write any JMX
code yourself, other than however you decide to fetch the information
from Tomcat.

>> I'm trying to determine the high-water mark over several days of 
>> typical use for how many concurrent connections are in use in
>> order to not over-allocate. I'm not 'managing' the connections.
>> I'm simply analyzing the usage of the pool.  I figured the most
>> obvious place to check in-use counts is each time a new
>> connection is allocated.
Fire up your favorite JMX client (I like VisualVM) and navigate here:

/Catalina/DataSource/[host]/[context-path]/javax.sql.DataSource/[datasou
rce-name]
and look at these attributes:

numActive
numIdle

I think that's everything you already want, right?

Also, if you don't want to over-allocate, let the connection pool
manage that:

maxTotal=20
maxIdle=5

If nobody is using the application, you'll end up with 5 connections
in the pool sitting idle after a while. f you have 10 users,
presumably, you'll hover at 10 connections bouncing between idle and
active for a while.

>>>> Each time a connection is requested, I have some jmx code
>>>> that logs values from the datasource mbean.
> That sounds wasteful. Why not interrogate the connection pool
> whenever a client probes the JMX bean?
> 
>> No clue what you mean here.  There's no situation where the
>> client has any reason to access a jmx bean.  I'm using the jmx
>> bean to collect and log the current state data for the datasource
>> pool each time a connection is requested from the pool.
> 
>> | >>  interrogate the connection pool
> 
>> Is there a way to get the jmx data such as in-use connection
>> count directly from the jdbc datasource object or some child
>> object?  I didn't see any methods on the datasource to give me
>> that data.  That's why I went to jmx to begin with.

The thing you are missing is that Tomcat already provides a bean in
the JMX tree that contains exactly what you are looking for. It
already keeps its stats up-to-date. You ust have to ask it for the
current state. From whatever component is interested.

If you want realtime stats on exactly when each event occurred  --
like an event log -- then you will indeed have to write a bunch of
code to do that. But it sounds to me like you are more interested in
what I would call "monitoring" than really getting a log of every event.

Have a look at slide 16 in this presentation:
http://tomcat.apache.org/presentations.html#latest-monitoring-with-jmx

> When/how are you binding your bean into the JNDI space?
> 
>> My code was in my original post.  Here it is again.

You've been around this community long enough to know I'm not a jerk.
So stop being a jerk to me. I read your code. I didn't see any object
binding.

>> I don't know if this the best way.  As I said, I found this code
>> by googling. It works. But it just dumps every jdbc datasource
>> mbean for all different resources without identifying them.  I'm
>> not creating and binding my own mbeans.  I'm simply finding beans
>> that already exist.
>> 
>> If there's a way to directly access the bean for a particular
>> datasource by name, can you show me the alternate code?
> 
>> MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 
>> Set<ObjectName> objectNames = server.queryNames(null, null); for
>> (ObjectName name : objectNames) { MBeanInfo info =
>> server.getMBeanInfo(name); if (info.getClassName().equals( 
>> "org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool"))  { for
>> (MBeanAttributeInfo mf : info.getAttributes()) {

It's not clear from this code that you are trying to hit a specific
bean (because you are hitting them all). It's not clear from this code
that you are looking for a container-managed bean versus some other
one -- maybe that you registered yourself.

It's very easy to look-up a specific bean from the MBeanServer. Are
you sure you need to do so? Here's the simple code to do it for an
example DataSource like the one in slide 16 of that presentation:

  MBeanServer server = ManagementFactory.getPlatformMBeanServer();
  ObjectName n = new
ObjectName("Catalina:type=DataSource,host=localhost,context=/examples,cl
ass=javax.sql.DataSource,name="jdbc/MyDataSource");
  Object o = server.getAttribute(n, "numActive");

For a DataSource mbean, the "numActive" attribute should be a
java.lang.Integer value. Where did I get that magic object name? I
used VisualVM to navigate the tree, found the object I was looking
for, and copy/pasted the object name directly from there.

On the other hand, maybe writing code to inspect the JMX bean isn't
what you want to do, either. If you just want to monitor the values,
you can use the JMXProxyServlet, which is one of my favorite tools.

In that same presentation, starting on page 38, there is information
about how to query JMX beans via HTTP from e.g. a monitoring system. I
think that might be what you are really looking for.

- -chris
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl3qcFcACgkQHPApP6U8
pFjUJQ//aZvsVDWC5VoT0zXnU6CLRRrfcMfWaAtjasLbERpS8Ht+OO2RlJulOTcG
OuyzjstAGtvjcO/GFgqzYNuOW5oKGHeWyiLPGLhIsk5we74mi7xY7szx4p/Di/3C
hFFBashFp2c5t75oc2Eg42L3YRk6jNtug9uvG6YBs5INKlIb1EcARzzR2xmkquvJ
/O89kovHLc14y+BXA1e/WNhWsJZPwoRae5g+UpwLFuRqE8SWYQ8EUJ+pm89XaZ6d
Hi6DzEfgSwVcMWC5HXe3bEPTJu8YNpepwT7KJXcZfyAjxRnASpnnApjezfJTqqgR
NxdXtr/QuRwrFu79HPLOu3XXs2gEuwkm4kXRzdHmEYdJShVh/ls92sII5NkqHCBR
2Xiwowsdd0XkhfmovLLh5dzYoVzWaot1/yLRCGtruLxPQmg+EFZouDPobqknBQZd
NtRuAAb64vQob/eQhM5sB3xEJi0NsPRKQZb9n06L4DEgifstLf6pmK9du+vPzxGG
fPA9KbdB7VbqgWbbL3ag5zBv03CH6YZkiEPWneulVFiuOC/6LvT2yqXT2Xrv2JUb
1y+50pYLkCcpbfTcxsIcEz1bZNghW+HTJadCeeuM5m76KzhUTy0yewtc22iu+9by
RGLg1/cRzS4zg77WhFsOxI77HEN8gInNZPNUhAm30oKWQKRKjSA=
=82AW
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: JMX 101 Question

Posted by Jerry Malcolm <te...@malcolms.com>.
Hi Chris,

See below

On 12/5/2019 1:07 PM, Christopher Schultz wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
>
> Jerry,
>
> On 12/5/19 13:42, Jerry Malcolm wrote:
>> I'm trying to add some code to monitor my jdbc data connection
>> pool.
> Before you do that, is this a pool that is application-managed? If
> Tomcat is managing the connection pool, then none of this is
> necessary. If it's application-managed, I'm curious as to why you are
> doing that rather than having Tomcat manage it for you. Would you mind
> explaining if that's the case?

It's tomcat managed.

| >> none of this is necessary

Are you telling me that it's unnecessary for me to know how many 
connections are currently in use in my connection pool??  I'm trying to 
determine the high-water mark over several days of typical use for how 
many concurrent connections are in use in order to not over-allocate.  
I'm not 'managing' the connections. I'm simply analyzing the usage of 
the pool.  I figured the most obvious place to check in-use counts is 
each time a new connection is allocated.

>> Each time a connection is requested, I have some jmx code that
>> logs values from the datasource mbean.
> That sounds wasteful. Why not interrogate the connection pool whenever
> a client probes the JMX bean?

No clue what you mean here.  There's no situation where the client has 
any reason to access a jmx bean.  I'm using the jmx bean to collect and 
log the current state data for the datasource pool each time a 
connection is requested from the pool.

| >>  interrogate the connection pool

Is there a way to get the jmx data such as in-use connection count 
directly from the jdbc datasource object or some child object?  I didn't 
see any methods on the datasource to give me that data.  That's why I 
went to jmx to begin with.

>
>> I haven't done much jmx coding.  So consider me a rookie on this
>> topic.  I found some code on the web that does pretty much what I
>> need. The relevant part of the code:
>>
>> MBeanServer server = ManagementFactory.getPlatformMBeanServer();
>> Set<ObjectName> objectNames = server.queryNames(null, null); for
>> (ObjectName name : objectNames) { MBeanInfo info =
>> server.getMBeanInfo(name); if (info.getClassName().equals(
>> "org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool"))  { for
>> (MBeanAttributeInfo mf : info.getAttributes()) {
>>
>> This code works.  The problem is that I have a bunch of virtual
>> hosts running on the same instance of TC.  So I get a bunch of
>> matching mbeans, apparently one for each virtual host / resource
>> defined.
>>
>> Is there any way to identify which mbean is for the datasource I
>> currently care about?  I was hoping there would be an attribute
>> with the datasource name or the database name or even just some way
>> to add a unique identifier when I create it.  But I don't see
>> anything.  I've resorted to having maxTotal set to incrementally
>> different values in all of my resource statements just so I can
>> identify the datasource I'm looking at in the logs.  But that's a
>> hack.
>>
>> Is there a better way to uniquely identify datasource mbeans in
>> jmx?
> Tomcat usually uses the JMX URI (?) space by adding the application's
> context-path (and possible hostname) as a part of the path to the
> bean. So for you that might be:
>
> com.yourcompany.yourapp/[host]/[app]/datasource
>
> When/how are you binding your bean into the JNDI space?

My code was in my original post.  Here it is again.  I don't know if 
this the best way.  As I said, I found this code by googling. It works.  
But it just dumps every jdbc datasource mbean for all different 
resources without identifying them.  I'm not creating and binding my own 
mbeans.  I'm simply finding beans that already exist.

If there's a way to directly access the bean for a particular datasource 
by name, can you show me the alternate code?

           MBeanServer server = ManagementFactory.getPlatformMBeanServer();
           Set<ObjectName> objectNames = server.queryNames(null, null);
           for (ObjectName name : objectNames) {
               MBeanInfo info = server.getMBeanInfo(name);
               if (info.getClassName().equals( 
"org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool"))  {
                   for (MBeanAttributeInfo mf : info.getAttributes()) {

                         <log the attr name and value>

>
> - -chris
> -----BEGIN PGP SIGNATURE-----
> Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/
>
> iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl3pVXQACgkQHPApP6U8
> pFiYkhAAj9UqGppFWTsvgiZg30BECln9mppvBCRGUSn/oV5SuGrRgpD+glcCWZEz
> ZRcLG1pDF8ze+sS57mU2oMIHO/vPuuBFKM4KmeyXbW1iIKF01PmQxmIG88qjgi2Z
> h2/AJKErGIpQ+GhrKSvX27vxrWzb1n7urCkq7PCCml5h20rl4OhaUnSmVGHQkr/6
> OlhmL45u2MdLMYAPDasf0bjrA0OPo3jFnn8myjtwVUjo2AGm6SS5RJn7HSB8QxqU
> ZNWnWiI40CaBGzJthDoRzKbspd+aCY/qM2dc6dIovL9hCCsEB+J6aJf9oE53+MyV
> 6md4wWBWVZSFzvkOg8Kjj+mx6QK/j9PC9HZ+nsbWk0kTfutCwZpQZQgtqe8tmAD9
> o/xvSUCSRig+PlMK1eYkkU5dYziI/FpWDhURg9zMXiXXnmRr6V2S4zNMK240Zxt1
> 1ev+QOucv4sjb+Nt8rUc1HazYfcZqfcI/fJjlNjPgPOkjRX3ftbbRIwDBVFwwCFv
> lOKt+fQvAZfM8pC7c50BLwl2fpvCRVt8+xHpp3t5EwKSycG55WsD9DmpMoLENNXp
> G+UDj+mmkIrPY5zHR+hqB2rMWABk084pWoNlBXlfApwqLcZq6h0fvV6E3IdvqRRD
> OhNwz1g2tF4HOgFlfVp0gfzzS9bnaNcgyGpXsrL4s/J8ZTVyfjs=
> =QuqP
> -----END PGP SIGNATURE-----
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: JMX 101 Question

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Jerry,

On 12/5/19 13:42, Jerry Malcolm wrote:
> I'm trying to add some code to monitor my jdbc data connection
> pool.

Before you do that, is this a pool that is application-managed? If
Tomcat is managing the connection pool, then none of this is
necessary. If it's application-managed, I'm curious as to why you are
doing that rather than having Tomcat manage it for you. Would you mind
explaining if that's the case?

> Each time a connection is requested, I have some jmx code that
> logs values from the datasource mbean.

That sounds wasteful. Why not interrogate the connection pool whenever
a client probes the JMX bean?

> I haven't done much jmx coding.  So consider me a rookie on this 
> topic.  I found some code on the web that does pretty much what I 
> need. The relevant part of the code:
> 
> MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 
> Set<ObjectName> objectNames = server.queryNames(null, null); for
> (ObjectName name : objectNames) { MBeanInfo info =
> server.getMBeanInfo(name); if (info.getClassName().equals( 
> "org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool"))  { for
> (MBeanAttributeInfo mf : info.getAttributes()) {
> 
> This code works.  The problem is that I have a bunch of virtual
> hosts running on the same instance of TC.  So I get a bunch of
> matching mbeans, apparently one for each virtual host / resource
> defined.
> 
> Is there any way to identify which mbean is for the datasource I 
> currently care about?  I was hoping there would be an attribute
> with the datasource name or the database name or even just some way
> to add a unique identifier when I create it.  But I don't see
> anything.  I've resorted to having maxTotal set to incrementally
> different values in all of my resource statements just so I can
> identify the datasource I'm looking at in the logs.  But that's a
> hack.
> 
> Is there a better way to uniquely identify datasource mbeans in
> jmx?

Tomcat usually uses the JMX URI (?) space by adding the application's
context-path (and possible hostname) as a part of the path to the
bean. So for you that might be:

com.yourcompany.yourapp/[host]/[app]/datasource

When/how are you binding your bean into the JNDI space?

- -chris
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Thunderbird - https://www.enigmail.net/

iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAl3pVXQACgkQHPApP6U8
pFiYkhAAj9UqGppFWTsvgiZg30BECln9mppvBCRGUSn/oV5SuGrRgpD+glcCWZEz
ZRcLG1pDF8ze+sS57mU2oMIHO/vPuuBFKM4KmeyXbW1iIKF01PmQxmIG88qjgi2Z
h2/AJKErGIpQ+GhrKSvX27vxrWzb1n7urCkq7PCCml5h20rl4OhaUnSmVGHQkr/6
OlhmL45u2MdLMYAPDasf0bjrA0OPo3jFnn8myjtwVUjo2AGm6SS5RJn7HSB8QxqU
ZNWnWiI40CaBGzJthDoRzKbspd+aCY/qM2dc6dIovL9hCCsEB+J6aJf9oE53+MyV
6md4wWBWVZSFzvkOg8Kjj+mx6QK/j9PC9HZ+nsbWk0kTfutCwZpQZQgtqe8tmAD9
o/xvSUCSRig+PlMK1eYkkU5dYziI/FpWDhURg9zMXiXXnmRr6V2S4zNMK240Zxt1
1ev+QOucv4sjb+Nt8rUc1HazYfcZqfcI/fJjlNjPgPOkjRX3ftbbRIwDBVFwwCFv
lOKt+fQvAZfM8pC7c50BLwl2fpvCRVt8+xHpp3t5EwKSycG55WsD9DmpMoLENNXp
G+UDj+mmkIrPY5zHR+hqB2rMWABk084pWoNlBXlfApwqLcZq6h0fvV6E3IdvqRRD
OhNwz1g2tF4HOgFlfVp0gfzzS9bnaNcgyGpXsrL4s/J8ZTVyfjs=
=QuqP
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: JMX 101 Question

Posted by Luis Rodríguez Fernández <uo...@gmail.com>.
Hello Jerry,

To be tested, but perhaps connectionProperties can help you on this? [1]

Hope it helps,

Luis

[1] https://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html

El jue., 5 dic. 2019 a las 19:42, Jerry Malcolm (<te...@malcolms.com>)
escribió:

> I'm trying to add some code to monitor my jdbc data connection pool.
> Each time a connection is requested, I have some jmx code that logs
> values from the datasource mbean.  I haven't done much jmx coding.  So
> consider me a rookie on this topic.  I found some code on the web that
> does pretty much what I need. The relevant part of the code:
>
>            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
>            Set<ObjectName> objectNames = server.queryNames(null, null);
>            for (ObjectName name : objectNames) {
>                MBeanInfo info = server.getMBeanInfo(name);
>                if (info.getClassName().equals(
> "org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool"))  {
>                    for (MBeanAttributeInfo mf : info.getAttributes()) {
>
> This code works.  The problem is that I have a bunch of virtual hosts
> running on the same instance of TC.  So I get a bunch of matching
> mbeans, apparently one for each virtual host / resource defined.
>
> Is there any way to identify which mbean is for the datasource I
> currently care about?  I was hoping there would be an attribute with the
> datasource name or the database name or even just some way to add a
> unique identifier when I create it.  But I don't see anything.  I've
> resorted to having maxTotal set to incrementally different values in all
> of my resource statements just so I can identify the datasource I'm
> looking at in the logs.  But that's a hack.
>
> Is there a better way to uniquely identify datasource mbeans in jmx?
>
> Thx
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

-- 

"Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better."

- Samuel Beckett