How do I set a custom subject in SmtpAppender in log4j2 - java

Our application is deployed as a servlet war to multiple tomcat servers under multiple customer contexts:
customer#application.war
We're using log4j2 as our logging and alert email mechanism. So far, everything is working great and our fatal errors are being sent. However, as we deploy to new contexts, it's becoming less clear which customer is generating the error.
So far, it appears that the subject value is static and set in the config file and the system variables are loaded when the logger is built:
subject="[${applicationname}] Fatal Error ${hostname}:${sys:pwd}"
While it appears that there is a way to ascertain the name of our deployed context via the servlet API, we have yet to determine how to introduce this value in the email subject programmatically and dynamically at run time.
This would greatly reduce the time it takes to research an error. Any tips?
So far we've considered the following:
Custom war file with custom log4j2 config for each customer context (very hackish)
Update all log.fatal calls to include the context info from the servlet (horrid)
Custom SmtpAppender (final and protected so that's out)
Custom SmtpManager and override the subject in the MimeMessage object (seems workable but the documentation does not show how to implement)
TIA!!
Piko

This is actually a known issue in Log4j2 as of 2.9.1. The problem is that a MimeMessage is cached and the subject becomes a fixed value. A simple solution would be to stop caching.
There is an open ticket to address this: Log4j2-1450. (Related: Log4j2-1192, which implemented pattern lookups but didn’t fix that MimeMessages are cached.)
If you can provide a patch or a pull request it would greatly increase the chances of this being addressed speedily.
Update: looking my old comment in that ticket:
Looks like subject already supports $$ runtime lookups. The following
attributes are used for each email that is sent, and it should be
possible to support runtime lookups for these attributes:
* from
* replyto
* to
* cc
* bcc
* subject (already a runtime lookup)
It should be possible to configure the subject to be a system properties lookup like this:
subject = "$${sys:email.subject}"
Then you set system property email.subject to a different subject and send an email with a different subject. Can you try this?
Update 2:
If system properties are not suitable, you can also create a custom lookup, this is only a few lines of code.

Related

Vaadin LitRenderer bean exposure to the client

Currently I'm using ComponentRenderers in my Vaadin application, but I would like to change it to LitRenderer (for better performance).
I read the documentation and I'm not sure about the "Note". Does it mean that the whole Person bean is exposed to the client, or only the Address bean from the example? I'm asking because I would like to use it for User bean which contains passwords...
https://vaadin.com/docs/latest/components/grid/flow#using-lit-renderers
As stated in the notes you have screenshoted. Only / all properties of the address is send to the client. If you would supply the user instance, the whole user instance' properties would be available in the client.

Shiro throws an UnavailableSecurityManagerException in custom JSON serialiser

I'm working on a REST API of a TomEE 7 based web app, which uses Shiro 1.3.2 for security. When an API request comes in, a SecurityManager and a Subject are created, and the latter is bound to a SubjectThreadState. I can call SecurityUtils.getSubject() anywhere in the endpoint code and the subject is always available.
However, problems arise when I try to do the same inside my custom JSON serialiser. It only serialises specific fields in some classes, so I register it on a per-field basis using this annotation:
#JsonSerialize(using = MySerialiser.class)
Long myRelatedItemId;
I wrote my serialiser based on the example code on this page under "2.7. #JsonSerialize". The serialiser needs to perform a cache lookup, and for that it has to have a Shiro subject. There is none because, thanks to the annotation above, I don't call the serialiser manually; instead Jersey calls it. This exception gets thrown (clarification: when I try to run SecurityUtils.getSubject() from the serialiser code):
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
at org.apache.shiro.subject.Subject$Builder.<init>(Subject.java:627)
at org.apache.shiro.SecurityUtils.getSubject(SecurityUtils.java:56)
I have confirmed that everything works if I call something like ObjectMapper().writeValueAsString() manually from the API endpoint code. However, that is definitely not the proper way to do it, because then the endpoint would effectively send and receive strings instead of the objects they are meant to handle.
I don't understand much about the inner workings of Shiro or Jackson, but it seems like the serialisation is being performed inside another thread, where Shiro's SubjectThreadState doesn't exist. Although if threading really is the cause, then I cannot see why Thread.currentThread().getName() returns the same value both inside and outside the serialiser, as does Thread.currentThread().getId().
I have tried a vast number of things to no avail, including:
Upgrading to Shiro 1.4.0.
Upgrading Jackson from 2.7.5 to 2.9.7.
Saving the SecurityManager instance that is created at the start of the API call inside a static ThreadLocal variable of the serialiser class.
Writing my own implementation of MessageBodyWriter which, not surprisingly, is called in exactly the same fashion.
Setting the staticSecurityManagerEnabled parameter to true in the ShiroFilter configuration in my web.xml.
Can anyone suggest how I could make the SecurityManager (or Subject) visible to the serialiser, when it's running in a thread not started by my code (clarification: or, otherwise running in parallel and started by Jersey, as far as I can tell)? Thanks in advance.
Update:
This stack trace was taken inside the serialiser:
<mypackage>.MySerializer.serialize()
com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField()
com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields()
com.fasterxml.jackson.databind.ser.BeanSerializer.serialize()
com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue()
com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize()
com.fasterxml.jackson.databind.ObjectWriter.writeValue()
com.fasterxml.jackson.jaxrs.base.ProviderBase.writeTo()
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo()
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo()
org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed()
org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo()
org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed()
org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo()
org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed()
org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo()
org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse()
org.glassfish.jersey.server.ServerRuntime$Responder.processResponse()
org.glassfish.jersey.server.ServerRuntime$Responder.process()
org.glassfish.jersey.server.ServerRuntime$2.run()
This one was taken in our interceptor class where the Subject is created and bound:
<mypackage>.MySecurityInterceptor.createSession()
sun.reflect.NativeMethodAccessorImpl.invoke0()
sun.reflect.NativeMethodAccessorImpl.invoke()
sun.reflect.DelegatingMethodAccessorImpl.invoke()
java.lang.reflect.Method.invoke()
org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke()
org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed()
org.apache.openejb.monitoring.StatsInterceptor.record()
org.apache.openejb.monitoring.StatsInterceptor.invoke()
sun.reflect.GeneratedMethodAccessor111.invoke()
sun.reflect.DelegatingMethodAccessorImpl.invoke()
java.lang.reflect.Method.invoke()
org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke()
org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed()
org.apache.openejb.core.interceptor.InterceptorStack.invoke()
org.apache.openejb.core.stateless.StatelessContainer._invoke()
org.apache.openejb.core.stateless.StatelessContainer.invoke()
org.apache.openejb.core.ivm.EjbObjectProxyHandler.synchronizedBusinessMethod()
org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod()
org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke()
org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke()
com.sun.proxy.$Proxy279.getEntity()
org.openapitools.api.impl.MyApiServiceImpl.getEntity()
org.openapitools.api.MyApi.getEntity()
sun.reflect.NativeMethodAccessorImpl.invoke0()
sun.reflect.NativeMethodAccessorImpl.invoke()
sun.reflect.DelegatingMethodAccessorImpl.invoke()
java.lang.reflect.Method.invoke()
org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke()
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run()
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke()
org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch()
org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch()
org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke()
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply()
org.glassfish.jersey.server.model.ResourceMethodInvoker.apply()
org.glassfish.jersey.server.ServerRuntime$2.run()
There are 46 more calls that are identical in both traces after that last line, so I excluded them. They contain a bunch of org.apache.catalina.core and org.glassfish.jersey.
Take a look at Shiro's Subject Thread Association doc

Dropwizard registering two classes/clients

I have two instances of clients with different configs that I am creating (timeout, threadpool, etc...), and would like to leverage Dropwizard's metric on both of the clients.
final JerseyClientBuilder jerseyClientBuilder = new JerseyClientBuilder(environment)
.using(configuration.getJerseyClientConfiguration());
final Client config1Client = jerseyClientBuilder.build("config1Client");
environment.jersey().register(config1Client);
final Client config2Client = jerseyClientBuilder.build("config2Client");
environment.jersey().register(config2Client);
However, I am getting
org.glassfish.jersey.internal.Errors: The following warnings have been detected:
HINT: Cannot create new registration for component type class org.glassfish.jersey.client.JerseyClient:
Existing previous registration found for the type.
And only one client's metric shows up.
How do I track both clients' metrics or is it not common to have 2 clients in a single dropwizard app?
Never mind, turned out I was an idiot (for trying to save some resource on the ClientBuilder).
2 Things that I did wrong with my original code:
1. You don't need to register Jersey clients, just the resource is enough... somehow I missed the resource part in my code and just straight up trying to register the client
2. You need to explicitly build each JerseyClientBuilder and then build your individually configured clients, then dropwizard will fetch by each JerseyClientBuilder's metrics
In the end, I just had to change my code to the following:
final Client config1Client = new JerseyClientBuilder(environment)
.using(configuration.getJerseyClientConfiguration()).build("config1Client");
final Client config2Client = new JerseyClientBuilder(environment)
.using(configuration.getJerseyClientConfiguration()).build("config2Client");
Doh.
environment.jersey().register() has a javadoc listing of Adds the given object as a Jersey singleton component meaning that the objects registered become part of the jersey dependency injection framework. Specifically this method is used to add resource classes to the jersey context, but any object with an annotation or type that Jersey looks for can be added this way. Additionally, since they are singletons you can only have one of them per any concrete type (which is why you are getting a "previous registration" error from Jersey).
I imagine that you want to have two Jersey clients to connect to two different external services via REST/HTTP. Since your service needs to talk to these others to do its work, you'll want to have the clients accessible wherever the "work" or business logic is being performed.
For example, this guide creates a resource class that requires a client to an external http service to do currency conversions. I'm not saying this is a great example (just a top google result for dropwizard external client example). In fact, I think this not a good to structure your application. I'd create several internal objects that hide from the resource class how the currency information is fetched, like a business object (BO) or data access object (DAO), etc.
For your case, you might want something like this (think of these as constructor calls). JC = jersey client, R = resource object, BO = business logic object
JC1()
JC2()
B1(JC1)
B2(JC2)
R1(B1)
R2(B2)
R3(B1, B2)
environment.jersey().register(R1)
environment.jersey().register(R2)
environment.jersey().register(R3)
The official Dropwizard docs are somewhat helpful. They at least explain how to create a jersey client; they don't explain how to structure your application.
If you're using the Jersey client builder from dropwizard, each of the clients that you create should be automatically registered to record metrics. Make sure you're using the client builder from the dropwizard-client artifact and package io.dropwizard.client. (Looks like you are because you have the using(config) method.)

How does one dynamically agree on a SenderCompID and TargetCompID in quickfixj?

Suppose that I'm running a web-based exchange and a new customer signs up. I give that customer a new CompID and now I want to add that CompID to my acceptor. Do I have to restart my acceptor or can that be done dynamically?
It doesn't seem very scalable to have to agree on the CompID ahead of time and then sticking it in a configuration somewhere.
I've seen some examples which supposedly do that, but they seem to simply change the configuration to pretty much ignore the Sender/Target CompID's by setting them to *. Any other ways to do that?
Take a look at the DynamicAcceptorSessionProvider and how it's used in the Executor example. The Executor example reads session "templates" from the settings file and associates these with the acceptor endpoint IP address. An acceptor template is identified by the "AcceptorTemplate=true" setting. Any of the session ID fields, including the FIX version, can be wildcarded, not just the SenderCompID.
See the executor_dynamic.cfg for an example of how session templates are defined. In this configuration, both the SenderCompID and TargetCompID are wildcarded and templates for various FIX versions are defined (to specify the appropriate data dictionary file).
When a message arrives for an unknown session ID, the DynamicAcceptorSessionProvider will try to match the session ID with a template's wildcarded sessionID. If it finds a match, the new session will be created automatically and added to the acceptor as if it had been explicitly defined in the settings. The new session will have the settings defined in the acceptor session template.
The DynamicAcceptorSessionProvider is an AcceptorSessionProvider implementation that uses the settings file to support dynamic session creation. However, you could also implement a custom AcceptorSessionProvider that could dynamically create sessions based on database information, for example.
I think you want to fix the TargetCompID and send a unique SenderCompID for each user to use. Then you set the SenderCompID in your acceptor config to *. This will allow the acceptance of all SenderCompIDs. However you will need to have somewhere in your code the facility to check each order against your database of users. If the user(SenderCompID) is not valid then you will send a reject message. Many implementations will also use tunnels and whitelisted IP addresses as well to make sure no unwanted connections are coming in.

Insert MBean interceptor

I am working in a java project which implements MBeans and my need is to intercept MBean and change/add their properties before registry. Example :
domainName:name=myMBean --> domainName:name=myMBean1,type=myType
I found this link which presents how to apply an interceptor other then default interceptor but I have no idea to how do that in code.
Thanks in advance.
Once you register the bean obviously it is too late. The easiest thing to do is to change how the registration is done. If you show us what framework you are using to register the bean then I'll be able to help more.
Typically whatever is doing the actual registration is doing something like:
private MBeanServer mbeanServer;
...
mbeanServer.registerMBean(mbean, objectName);
You can therefore provide a different ObjectName:
ObjectName objectName = new ObjectName("domainName:name=myMBean1,type=myType");
But I assume you are not doing the registration yourself.
As an aside, I'm not sure you can switch to use a different JMX framework but I've put the finishing touches on my Simple JMX system recently. It allows objects to name themselves programmatically when they are published.

Categories

Resources