Re: servletcontext.log filename

2021-12-01 Thread Rob Sargent




On 12/1/21 12:32 PM, Mark Thomas wrote:

On 01/12/2021 19:24, Rob Sargent wrote:
I'm using an embedded tomcat (ver9.0.54) and I don't see how to 
name/redirect the output of ServletContext.log(String).


I see in the manual

    This logging is performed according to the Tomcat logging
    configuration. You cannot overwrite it in a web application.

I missing the "Tomcat logging config" bit, I guess.


Each web application gets its own logger and these messages are 
directed there. The loggers are named along these lines:



org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/examples]

Adjust as necessary for your engine name, host name and context path.

Mark


Call off the dogs: I found the logs (carefully hidden in stdout...)

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



Re: NPE in request.getRequestURL()

2021-12-01 Thread Christopher Schultz

Jerry,

On 12/1/21 11:44, Jerry Malcolm wrote:

Chris,


On 11/30/2021 11:41 PM, Jerry Malcolm wrote:


On 11/30/2021 1:58 PM, Christopher Schultz wrote:

Jerry,

On 11/30/21 14:17, Jerry Malcolm wrote:

Chris, Thanks for the response.

Sorry... forgot to include the TC ver -- 8.5.69.

I had a situation a while back where I spun a longrunning thread and 
held the request object after the main response was returned. I 
fixed that situation.  In this situation, it is occurring on the 
main request/response thread.  Is there any situation where the 
request object could be recycled before the associated response is 
returned?


Not usually. So the thread hitting the NPE is something like 
[catalina-exec- ...]?


And you are sure you aren't doing anything funny with the request 
object? No storing it in the session or getting a reference from some 
cross-thread storage mechanism?


Looking at the code 
(https://github.com/apache/tomcat/blob/8.5.x/java/org/apache/catalina/connector/Request.java#L2465): 



    @Override
    public StringBuffer getRequestURL() {

    StringBuffer url = new StringBuffer();
    String scheme = getScheme();
    int port = getServerPort();
    if (port < 0)
 {
    port = 80; // Work around java.net.URL bug
    }

    url.append(scheme);
    url.append("://");
    url.append(getServerName());
    if ((scheme.equals("http") && (port != 80))
    || (scheme.equals("https") && (port != 443))) {
    url.append(':'); //  This is line 2465
    url.append(port);
    }
    url.append(getRequestURI());

    return url;
    }

I don't see how an NPE could happen on that line.

But 8.5.69 was released on 2021-07-05, and that code is here:

https://github.com/apache/tomcat/blob/3e9dd49b20f9d6e270f8709d4f16d5595977595e/java/org/apache/catalina/connector/Request.java 



This makes a little more sense:

    @Override
    public StringBuffer getRequestURL() {

    StringBuffer url = new StringBuffer();
    String scheme = getScheme();
    int port = getServerPort();
    if (port < 0)
 {
    port = 80; // Work around java.net.URL bug
    }

    url.append(scheme);
    url.append("://");
    url.append(getServerName());
    if ((scheme.equals("http") && (port != 80)) // <<< This is 2465
    || (scheme.equals("https") && (port != 443))) {
    url.append(':');
    url.append(port);
    }
    url.append(getRequestURI());

    return url;
    }

So the scheme is null. That's odd, since getScheme is:

    public String getScheme() {
    return coyoteRequest.scheme().toString();
    }

Oh, but coyoteRequest.scheme() returns a MessageBytes object whose 
toString method can (somewhat surprisingly) return null(!) when the 
type is T_NULL. And wouldn't you know it, here is the code for 
MessageBytes.recycle() (which gets called whenever the request, and 
therefore all of the various parts of the request, is recycled):


    public void recycle() {
    type=T_NULL;
    byteC.recycle();
    charC.recycle();

    strValue=null;

    hasStrValue=false;
    hasHashCode=false;
    hasLongValue=false;
    }

So it definitely looks like your request has been recycled somehow.

-chris

Chris, I was running 8.5.69.  (I just bumped to 8.5.72).  So I agree 
that everything looks like a recycled request.  This is a REST api. 
Pretty much come in, do the work, return.  The request object is 
carried around throughout the api in a 'briefcase' object.  But 
nothing is cached in the session object or anywhere. Pretty much a new 
sunrise on every api/servlet call coming in.


Just to confirm my understanding of request recycling, a request 
object is assigned before the request is handed to my handler 
servlet.  When the servlet exits, the request object is recycled and 
returned to the pool.   For this problem to be a recycled request 
problem, it would mean that I saved off a reference to a request and 
referenced it on a different servlet call.  It would have to be on a 
different call, since the service of the api is a single thread in and 
out.  I've been around too long to say that it couldn't happen.  But 
at this point, I'm struggling with how. It would mean I would have to 
discard the correct request for the servlet call and replace it with 
an old version.  I'm going to have add some logging statements.  Is 
there a unique id or something for each request object in the pool 
that I might be able to get access to?  If so, I can start logging the 
request UID at the beginning of the servlet call and log the UID on 
each access to the request object.


Let me know if there's some magic ID I can log to try to figure out 
when i might be using a recycled instance?


Thx

Jerry


Problem solved.  You were right about it being a recycled request 
object.  I had convinced myself the problem was occurring during one 

Re: servletcontext.log filename

2021-12-01 Thread Rob Sargent




On 12/1/21 12:32 PM, Mark Thomas wrote:

On 01/12/2021 19:24, Rob Sargent wrote:
I'm using an embedded tomcat (ver9.0.54) and I don't see how to 
name/redirect the output of ServletContext.log(String).


I see in the manual

    This logging is performed according to the Tomcat logging
    configuration. You cannot overwrite it in a web application.

I missing the "Tomcat logging config" bit, I guess.


Each web application gets its own logger and these messages are 
directed there. The loggers are named along these lines:



org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/examples]

Adjust as necessary for your engine name, host name and context path.

Mark



I'm sorry, but my servlet calls to log("something") seem to be going to 
/dev/null.  I can't find them anywhere.  I'm operating on a CentOS 7 not 
under my management (so no IDE to look at the values of interest).



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



Re: servletcontext.log filename

2021-12-01 Thread Mark Thomas

On 01/12/2021 19:24, Rob Sargent wrote:
I'm using an embedded tomcat (ver9.0.54) and I don't see how to 
name/redirect the output of ServletContext.log(String).


I see in the manual

    This logging is performed according to the Tomcat logging
    configuration. You cannot overwrite it in a web application.

I missing the "Tomcat logging config" bit, I guess.


Each web application gets its own logger and these messages are directed 
there. The loggers are named along these lines:



org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/examples]

Adjust as necessary for your engine name, host name and context path.

Mark

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



servletcontext.log filename

2021-12-01 Thread Rob Sargent
I'm using an embedded tomcat (ver9.0.54) and I don't see how to 
name/redirect the output of ServletContext.log(String).


I see in the manual

   This logging is performed according to the Tomcat logging
   configuration. You cannot overwrite it in a web application.

I missing the "Tomcat logging config" bit, I guess.




Re: NPE in request.getRequestURL()

2021-12-01 Thread Jerry Malcolm

Chris,


On 11/30/2021 11:41 PM, Jerry Malcolm wrote:


On 11/30/2021 1:58 PM, Christopher Schultz wrote:

Jerry,

On 11/30/21 14:17, Jerry Malcolm wrote:

Chris, Thanks for the response.

Sorry... forgot to include the TC ver -- 8.5.69.

I had a situation a while back where I spun a longrunning thread and 
held the request object after the main response was returned. I 
fixed that situation.  In this situation, it is occurring on the 
main request/response thread.  Is there any situation where the 
request object could be recycled before the associated response is 
returned?


Not usually. So the thread hitting the NPE is something like 
[catalina-exec- ...]?


And you are sure you aren't doing anything funny with the request 
object? No storing it in the session or getting a reference from some 
cross-thread storage mechanism?


Looking at the code 
(https://github.com/apache/tomcat/blob/8.5.x/java/org/apache/catalina/connector/Request.java#L2465):


    @Override
    public StringBuffer getRequestURL() {

    StringBuffer url = new StringBuffer();
    String scheme = getScheme();
    int port = getServerPort();
    if (port < 0)
 {
    port = 80; // Work around java.net.URL bug
    }

    url.append(scheme);
    url.append("://");
    url.append(getServerName());
    if ((scheme.equals("http") && (port != 80))
    || (scheme.equals("https") && (port != 443))) {
    url.append(':'); //  This is line 2465
    url.append(port);
    }
    url.append(getRequestURI());

    return url;
    }

I don't see how an NPE could happen on that line.

But 8.5.69 was released on 2021-07-05, and that code is here:

https://github.com/apache/tomcat/blob/3e9dd49b20f9d6e270f8709d4f16d5595977595e/java/org/apache/catalina/connector/Request.java 



This makes a little more sense:

    @Override
    public StringBuffer getRequestURL() {

    StringBuffer url = new StringBuffer();
    String scheme = getScheme();
    int port = getServerPort();
    if (port < 0)
 {
    port = 80; // Work around java.net.URL bug
    }

    url.append(scheme);
    url.append("://");
    url.append(getServerName());
    if ((scheme.equals("http") && (port != 80)) // <<< This is 2465
    || (scheme.equals("https") && (port != 443))) {
    url.append(':');
    url.append(port);
    }
    url.append(getRequestURI());

    return url;
    }

So the scheme is null. That's odd, since getScheme is:

    public String getScheme() {
    return coyoteRequest.scheme().toString();
    }

Oh, but coyoteRequest.scheme() returns a MessageBytes object whose 
toString method can (somewhat surprisingly) return null(!) when the 
type is T_NULL. And wouldn't you know it, here is the code for 
MessageBytes.recycle() (which gets called whenever the request, and 
therefore all of the various parts of the request, is recycled):


    public void recycle() {
    type=T_NULL;
    byteC.recycle();
    charC.recycle();

    strValue=null;

    hasStrValue=false;
    hasHashCode=false;
    hasLongValue=false;
    }

So it definitely looks like your request has been recycled somehow.

-chris

Chris, I was running 8.5.69.  (I just bumped to 8.5.72).  So I agree 
that everything looks like a recycled request.  This is a REST api.  
Pretty much come in, do the work, return.  The request object is 
carried around throughout the api in a 'briefcase' object.  But 
nothing is cached in the session object or anywhere. Pretty much a new 
sunrise on every api/servlet call coming in.


Just to confirm my understanding of request recycling, a request 
object is assigned before the request is handed to my handler 
servlet.  When the servlet exits, the request object is recycled and 
returned to the pool.   For this problem to be a recycled request 
problem, it would mean that I saved off a reference to a request and 
referenced it on a different servlet call.  It would have to be on a 
different call, since the service of the api is a single thread in and 
out.  I've been around too long to say that it couldn't happen.  But 
at this point, I'm struggling with how. It would mean I would have to 
discard the correct request for the servlet call and replace it with 
an old version.  I'm going to have add some logging statements.  Is 
there a unique id or something for each request object in the pool 
that I might be able to get access to?  If so, I can start logging the 
request UID at the beginning of the servlet call and log the UID on 
each access to the request object.


Let me know if there's some magic ID I can log to try to figure out 
when i might be using a recycled instance?


Thx

Jerry


Problem solved.  You were right about it being a recycled request 
object.  I had convinced myself the problem was occurring during one of 
the direct api calls.  When I traced back 

Re: BasicDataSource restart()

2021-12-01 Thread Jerry Malcolm

Mark,

On 12/1/2021 12:21 AM, Mark Eggers wrote:

Jerry,

On 11/30/2021 10:06 PM, Jerry Malcolm wrote:
I'm circling back to this after a few months.  I am building on a 
Windows 10 box with 9.0.52 TC.  But I'm running on an AWS Linux2 with 
8.5.72.  This has never caused any problems so far, or at least as 
far as I can tell.  But I'm hitting something strange with this 
relatively new BasicDataSource.restart() method.   My reference to 
restart() builds fine.  But when I run it on the 8.5.72 server I get: 
java.lang.NoSuchMethodError: 'void 
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.restart()'


Rémy mentioned that it should be in TC 8.5.58+.   This is a 
relatively clean EC2 on AWS, not running much other than Tomcat. And 
I have not done in backdoor (non yum) installs of TC that might have 
left old jar files around.   I noticed that there are 2 dbcp2 jar 
files in TC's lib. One is from the java install. But the error 
message above is a tomcat path.  So I'm assuming it's tomcat's dbcp2 
jar that's being referenced. I exploded the jar hoping there would be 
some version numbers somewhere inside telling me if I somehow have a 
backlevel jar.  But I couldn't find anything.  All I know is it's 
date is 2/25/2021 and it's 286,358 bytes.


Any other ideas come to mind why it's telling me the restart() method 
doesn't exist?


Thx as always.

Jerry


On 9/7/2021 2:49 PM, Jerry Malcolm wrote:


On 9/7/2021 2:35 PM, Christopher Schultz wrote:

Jerry, Rémy,

On 9/3/21 07:15, Rémy Maucherat wrote:
On Fri, Sep 3, 2021 at 2:46 AM Jerry Malcolm 
 wrote:


I have a requirement to start a new log database on the first of 
every
month.  I still need to have access to older monthly log 
databases.   I

do not want to create a bunch of hardcoded manually configured
individual datasources, one for each month.  I have a dynamic 
datasource

solution that is completely implemented and working except for one
little thing.

I access the BasicDataSource implementation class for the 
datasource.  I
have an algorithm that substitutes _MM at the appropriate 
spot in
the configured URL and then updates the url in the datasource. 
All of
this works great.  I can live with the fact that the datasource 
can only
point to one database at a time.  My concern is that once I 
transition
to another database, there are existing connections in the pool 
that are

already attached to the old database.  I need to clear those out and
start over.  But I don't have the luxury of bouncing tomcat to 
clean it up.


The apache commons BasicDataSource has a restart() method. But
unfortunately that method is omitted from the Tomcat version. 
There is a
close() method on the BasicDataSource.  But I don't see anything 
that
will re-open it after closing.  I thought about changing 
maxActive to 0,

and waiting for it to drain, then setting it back to the original
value.  None of these sound like an ideal solution. Without a 
restart()

method, is there any other way to force all existing connections to
close and start clean?


The code is kept in sync with DBCP (with a bit of lag maybe), so 
these

lifecycle methods were also added to Tomcat one year ago (9.0.38+ and
8.5.58+).


We are using this at $work to bounce our database connection pools 
after TLS client certificate changes. This is the code we are using 
to reload the pool:


  try
  {
  Context ctx = new InitialContext();

  DataSource ds = (DataSource)ctx.lookup(getJNDIPath());

  if(null == ds)
  throw new ServiceException("Cannot obtain DataSource");

  if(isInstanceOf(ds, 
"org.apache.tomcat.dbcp.dbcp2.BasicDataSource")
 || isInstanceOf(ds, 
"org.apache.commons.dbcp2.BasicDataSource")) {


  return call(ds, "restart");
  }
  } catch (Exception e) {
org.apache.log4j.Logger.getLogger(this.getClass()).error("Failed to 
reload DataSource " + getJNDIPath());

  }

The call() method simply encapsulates all of the work to make a 
reflective method call to BasicDataSource.restart().


As Rémy points out, it requires a Tomcat version 9.0.38+ or 8.5.58+.

Hope that helps,
-chris


Chris,

I'll definitely try this.  But I'm curious about the restart method. 
Is it some sort of a hidden method that's only available to 
reflection?  Seems it would be a lot more straightforward to just 
make the restart method public like it is in the apache version of 
BasicDataSource.  I'm not complaining.  If this works, then fine. 
Just curious.


Thx

Jerry


I haven't been following this thread, so I may be way off.

The last time I used an AWS EC2 instance "out of the box" with an 
AWS-supplied Tomcat, I ran into some very strange behavior.


It turns out that AWS packaged the 8.5.x Tomcat with the older (7.0.x) 
resource pool. I figured this out by looking at logs and seeing the 
complaints about my context.xml.


I raised the issue with AWS, and got silence back.

Ever since then, I package up my own version of Tomcat using releases 
from tomcat.apache.org.