-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dhdoshi/spring boot name bug #411
Conversation
See the checklist in PR description? Please follow the check boxes:
Also make sure that the new public method has a Javadoc with explanation how it when to use it. |
@@ -59,20 +58,24 @@ | |||
private boolean agentIsUp = false; | |||
private final LinkedList<ThreadLocalCleaner> cleaners = new LinkedList<ThreadLocalCleaner>(); | |||
|
|||
//Only for Spring Boot Application (External Name Setting) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to limit use of it for Spring Boot. May one decide to do it in regular app?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not quite sure about it, may be I am wrong though. I think other application like Spring/Jsp/Servlet etc they pick up configuration with xml files. However, in Spring boot configuration is done with Java classes and application name is set using application.properties file. Therefore there was a need to explicitly set the name. Correct me if I am wrong here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- As soon as we make new constructor public, we cannot control if it's going to be used for Spring Boot only or not.
- There might be another framework we haven't tried yet that required application name setup outside of configuration xml files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a side note - is there any implication if name is set in both configuration and the code with this constructor for non-SpringBoot app? Name from the code will take precedence and any mappings created for the previous name will be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dmitry-Matveev I believe that the name from the code will take precedence as the getName() method will return after executing the if statement as soon as it sees the name is set externally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhaval24 , Thank for looking into this! Then the question is - will changing name right in the code affect the behavior of the SDK in some unpredictable way?
For example, if name from the code takes precedence, could it be that some configuration settings are not picked up (simply because they are mapped to the name used in the configuration but not in code)? If no such or similar case is possible - we should be OK with this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dmitry-Matveev honestly, I am not quite sure if this can affect the SDK in some unpredictable way. Do you have any ideas how I can check this?
@@ -257,6 +265,12 @@ private String registerWebApp(String name) { | |||
} | |||
|
|||
private String getName(ServletContext context) { | |||
|
|||
// If Application is of type Spring Boot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, do not limit it to spring boot only
@@ -59,20 +58,24 @@ | |||
private boolean agentIsUp = false; | |||
private final LinkedList<ThreadLocalCleaner> cleaners = new LinkedList<ThreadLocalCleaner>(); | |||
|
|||
//Only for Spring Boot Application (External Name Setting) | |||
private String applicationName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make it final
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure can make that as final
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SergeyKanzhelev I just looked into the code and it seems that we cannot make the applicationName final because if we do so it has to be initialized in the constructor itself (either through parameterized constructor or default constructor) and we do not have a way to do it with default constructor because with non spring boot application the name of the application is caught from the servlet context and in our implementation it is retrieved from getName() method which parses the context and is invoked post constructor call. Let me know.
@@ -59,20 +58,24 @@ | |||
private boolean agentIsUp = false; | |||
private final LinkedList<ThreadLocalCleaner> cleaners = new LinkedList<ThreadLocalCleaner>(); | |||
|
|||
//Only for Spring Boot Application (External Name Setting) | |||
private String applicationName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how applicaitonName
will be used? Is it send along the telemetry? If it will end up as roleName
- worse naming it appropriately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For, this one I have a question too. I think even without setting the name Telemetry flows in the portal. Only it comes in AI logs. I don' know the exact implication of it, in this context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhaval24 , please check where this name is used through the code and whether it makes it into the telemetry item at all. If not, keeping it as applicationName
is ok.
@@ -59,20 +58,24 @@ | |||
private boolean agentIsUp = false; | |||
private final LinkedList<ThreadLocalCleaner> cleaners = new LinkedList<ThreadLocalCleaner>(); | |||
|
|||
//Only for Spring Boot Application (External Name Setting) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- As soon as we make new constructor public, we cannot control if it's going to be used for Spring Boot only or not.
- There might be another framework we haven't tried yet that required application name setup outside of configuration xml files.
@@ -59,20 +58,24 @@ | |||
private boolean agentIsUp = false; | |||
private final LinkedList<ThreadLocalCleaner> cleaners = new LinkedList<ThreadLocalCleaner>(); | |||
|
|||
//Only for Spring Boot Application (External Name Setting) | |||
private String applicationName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhaval24 , please check where this name is used through the code and whether it makes it into the telemetry item at all. If not, keeping it as applicationName
is ok.
@@ -59,20 +58,24 @@ | |||
private boolean agentIsUp = false; | |||
private final LinkedList<ThreadLocalCleaner> cleaners = new LinkedList<ThreadLocalCleaner>(); | |||
|
|||
//Only for Spring Boot Application (External Name Setting) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a side note - is there any implication if name is set in both configuration and the code with this constructor for non-SpringBoot app? Name from the code will take precedence and any mappings created for the previous name will be ignored.
|
||
/*For Parametrized constructor testing*/ | ||
private FilterAndTelemetryClientMock createInitializedParametrizedFilterWithMockTelemetryClient(boolean withTelemetryClient, boolean clientThrows) throws ServletException, NoSuchFieldException, IllegalAccessException { | ||
Filter filter = createParametrizedInitializedFilter("My-App"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no validation that "My-app" has actually made it though and changed the way the code works.
You may want to add a test that checks my-app assignment or tests a change in the execution flow caused by the name being pre-assigned.
@SergeyKanzhelev @Dmitry-Matveev In the recent commits, I have removed the public constructor as it could have possible consequences of breaking other components like java agent, because whenever you set the name of the web-app it also gets the same name registered with the Java Agent and this only happens initially. Now if we expose public constructor, then someone might change the name of the application in the middle of the execution and in this case Java Agent might get unhooked. There were couple of work-arounds that I had:
However, one caveat - this is still a patch, a full fleged solution would be to like having another config module similar to what we have for XML, though its worth while to investigate if we need those efforts at all. Please provide your suggestions. |
* Parameterized constructor, used to set Application name explicitly | ||
* @param applicationName | ||
*/ | ||
public WebRequestTrackingFilter(String applicationName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like public constructor is still present - maybe merge issue?
} | ||
|
||
properties.load(input); | ||
name = properties.getProperty("spring.application.name"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it the way we're going to use for spring only or the name should be more generic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dmitry-Matveev yes as of now I am not aware of any other framework that reads the value from the properties file though this is through a very preliminary research. There can be places where this is the only way but not in my knowledge. For all other cases we are already reading from application context. Also just pushed the corrected version where the public constructor has been removed which was accidentally present in the previous commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This property is going to be our public interface to configure application name that something can take dependency on, so changing it once released is not an easy task.
I think renaming this property before release to a more generic scope rather than "spring" will make us stay on the safe side and prevent "deprecation"/rename issues in the future.
@@ -284,6 +301,38 @@ private String getName(ServletContext context) { | |||
return name; | |||
} | |||
|
|||
/*This method is used to parse application name from the properties file*/ | |||
private String getApplicatioNameFromProperties() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to add a unit test for this new behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dmitry-Matveev I agree that there should be test to test this behavior. However the WebRequestTrackingFilter does not implement any interface that we can mock using Mockito framework. The only way that we can write a testcase for this using JUnit can be actually reading from the file and doing the verification. Now that comes with a caveat. We need to store that file into our source code somewhere. If you have any other ideas on testing let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make WebRequestTrackingFilter
implement an interface if it's required for tests since you control the code. Storing file within test project for test purposes is perfectly fine - you can consider such a file a 'test resource'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Dmitry-Matveev interface will not help here, mocking interface makes only interface methods available for mocking. Better to make class not final and Mockito will be able to mock it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gavlyukovskiy, makes sense. @dhaval24, could you please take a look at this approach?
Hard coding getting property I understand that
|
@gavlyukovskiy, I remember @dhaval24 was trying to address this with the constructor but as far as I remember the continuation on this, the things didn't play well down the road for some reason. @dhaval24 would have more details to share. |
@gavlyukovskiy I wast taking the exact same approach as you suggested in the first place however after some digging into the code I found that. we use the same name to bind Java Agent also. As I expressed in the previous comments on this PR there is possible risk of de-binding the agent from SDK because the person might be able to change the name of the field by calling the public constructor with argument. However, if I think deeply on this the constructor is only called when the user intents to get a new instance and hence might be okay. However, the issue with this approach is that we might expose a public constructor which is not required at all. Also, when I was dealing with this I had an opinion that we might need a separate module to read the configurations from the properties file in the same way as we do for XML because I believe that there are several spring boot applications that are standalone only and doesn't have War files, these applications don't have any xml files in theory so it would be best if we can read all the config from properties file but then we had a discussion that is it worth the effort and therefore we haven't proceed on this yet. Let me know if you have any better ideas other than public constructor (may be addressing wider problems relating to spring boot) |
Reading configuration from properties will not help much for Spring Boot users. It is not just read application.properties because of
The only way to handle this is using Spring classes that are aware of those type of configuration - If you want to support Spring Boot I think the better way is to add some property map (or tags) in your If you want to look at starter examples you may refer to 3rd-party spring boot starters page or to my project with few starters for data source decorating libraries. We in Cloudyn (Azure Cost Management) are interested in integration with Application Insights as all our applications are spring boot we anyhow will create some kind of a starter for our needs. If spring boot is in your priorities we can cooperate on this, my Microsoft email is [email protected]. |
@gavlyukovskiy This makes much more sense to me now. Totally agree with your point that reading from properties won't suffice. Thanks for your interest in using Application Insights and definitely SpringBoot is one of the most popular web frameworks in Java community and it makes sense to have first class support for SpringBoot. I will start an email thread with you. |
Closing this PR as public constructor is now introduced to support this as part of #449 PR Merge |
#461 is still active and work will be in progress on that. |
Fix #359

For significant contributions please make sure you have completed the following items: