We're using Spring Boot for an application, with Camel for routing. We split most routes with an endpoint "URI" String, mainly for testability's sake:
rest("/foo").post().to("direct:foo");
from("direct:foo").process(exchange -> {
exchange.getIn().setBody(service.doStuff());
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, CONTENT_TYPE_JSON);
});
However if we mis-type one of the "direct:foo" strings, we don't get an error until the route is invoked. I'd like to be able to get the error earlier, as part of the application's startup process.
Obviously using static finals instead of String literals will keep us from mis-typing an individual endpoint value, but it won't help with the situation where one endpoint doesn't go anywhere, or we're using one for a from without sending anything to it.
Is there a way I can ask Camel to verify all routes have working to/from endpoints, once Spring has finished scanning the classpath and building beans?
Related
I am creating an controller where there is certain attributes in json which is an doing in postman a POST request like this if all attributes are posted then its fine
if one then is missing then it would look like this
i want this response when some attribute is missing how to implement this
This is normally implemented in two steps:
Implement a validation mechanism for the method that handles the incoming request. Normally you would throw an exception here if the input is incorrect, in your example a missing JSON key.
Implement a global error handler that will process the exception from point 1 and format the response as JSON.
For point 1 the usual choice is the Java Bean Validation framework because it's integrated with Spring Boot and allows to define validation constraints with annotations like #NotEmpty. You can take a look at this example.
For point 2 the usual choice is #RestControllerAdvice or #ControllerAdvice. You would have to understand your service web server setup to implement it properly e.g. it might behave differently if you use Spring WebFlux.
I want to find the actual java class that serves the Spring Actuator endpoint (/actuator).
It's similar to this question in a way, but that person wanted to call it via a network HTTP call. Ideally, I can call it within the JVM to save on the cost of setting up an HTTP connection.
The reason for this is because we have 2 metrics frameworks in our system. We have a legacy metrics framework built on OpenCensus and we migrated to Spring Actuator (Prometheus metrics based on Micrometer). I think the Spring one is better but I didn't realize how much my company built infrastructure around the old one. For example, we leverage internal libraries that use OpenCensus. Infra team is depending on Opencensus-based metrics from our app. So the idea is to try to merge and report both sets of metrics.
I want to create my own metrics endpoint that pulls in data from Opencensus's endpoint and Actuator's endpoint. I could make an HTTP call to each, but I'd rather call them within the JVM to save on resources and reduce latency.
Or perhaps I'm thinking about it wrong. Should I simply be using MeterRegistry.forEachMeter() in my endpoint?
In any case, I thought if I found the Spring Actuator endpoint, I can see an example of how they're doing it and mimic the implementation even if I don't call it directly.
Bonus: I'll need to track down the Opencensus handler that serves its endpoint too and will probably make another post for that, but if you know the answer to that as well, please share!
I figured it out and posting this for anyone else interested.
The key finding: The MeterRegistry that is #Autowired is actually a PrometheusMeterRegistry if you enable the prometheus metrics.
Once you cast it into a PrometheusMeterRegistry, you can call its .scrape() method to return the exact same metrics printout you would when you hit the http endpoint.
I also need to get the same info from OpenCensus and I found a way to do that too.
Here's the snippet of code for getting metrics from both frameworks
Enumeration<MetricFamilySamples> openCensusSamples = CollectorRegistry.defaultRegistry.filteredMetricFamilySamples(ImmutableSet.of());
StringWriter writer = new StringWriter();
TextFormat.write004(writer, openCensusSamples);
String openCensusMetrics = writer.toString();
PrometheusMeterRegistry registry = (PrometheusMeterRegistry) meterRegistry;
String micrometerMetrics = registry.scrape();
return openCensusMetrics.concat(micrometerMetrics);
I found out another interesting way of doing this.
The other answer I gave but it has one issue. It contains duplicate results. When I looked into it, I realized that both OpenCensus and Micrometer were reporting the same result.
Turns out that the PrometheusScrapeEndpoint implementation uses the same CollectorRegistry that OpenCensus does so the both sets of metrics were being added to the same registry.
You just need to make sure to provide these beans
#PostConstruct
public void openCensusStats() {
PrometheusStatsCollector.createAndRegister();
}
#Bean
public CollectorRegistry collectorRegistry() {
return CollectorRegistry.defaultRegistry;
}
The problem
I have a spring mvc application that uses apache camel. I am confused on the role that the RouteBuilder class plays and how it actually gets initialized. I know that the docs say that the configure() method is:
Called on initialization to build the routes using the fluent builder syntax.
but when does this initialization occur? Does it occur at application startup or some time later when the route is about to be used?
The purpose of this question is ultimately to ask how I can modify the route at runtime. I want to be able to build different routes as needed.
Examples
xml definitions:
<service name="myService" tier="3">
<requestType>my.package.RequestType</requestType>
<responseType>my.package.ResponseType</responseType>
<endpoint>
<httpEndpoint>
<url default="true" value="someUrl"/>
<timeout value="5000"/>
</httpEndpoint>
</endpoint>
</service>
Route Builder template:
public class myRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// When does this method get executed?
}
}
Questions
When does configure() execute?
How can I dynamically set the endpoint url?
You are able to use toD to dynamically change the endpoint at runtime based on an expression. See the documentation
If you want to change more of the route or add a completely new route then look at the API on the CamelContext. This Stackoverflow question has an example of adding a completely new route.
The lifecycle of the Camel service is documented here : https://camel.apache.org/lifecycle.html
Camel uses a simple lifecycle interface called Service which has a single start() and stop() method.
Various classes implement Service such as CamelContext along with a number of Component and Endpoint classes.
When you use Camel you typically have to start the CamelContext which will start all the various components and endpoints and activate the routing rules until the context is stopped again.
It is when the context starts that the various components start. Not sure i understand the dynamic url part. If it is to indicate a dynamic endpoint (if the data is this , then queue1 else queue2) you should be able to use something like the DynamicRouter EIP which is as explained here (https://camel.apache.org/dynamic-router.html)
You have several options.
Inject them as spring properties.
Inject them from external properties source.
Inject them from some bean method.
Then you can put the property value in a header and later put the value in the .toD("$header.routeEndpoint"). This can take care of dynamic endpoints.
Off course to rebuild the entire route you need to play with the API.
I am planning to use one of the above servlets. My use case is, client hits one of the server [This is where I would be using Proxy or MiddleMan servlet]. From here I would like to talk to other services based on the request URL. Can I use these servlets for this use case
example:
client -->http://<headend>/service1/x/y ---In MiddleManServlet -- http://server1/service1/x/y
client -->http://<headend>/service2/x/y ---In MiddleManServlet -- http://server2/service2/x/y
Can this be accomplished using this servlets?. I know I have to override rewriteTarget method.
Yes, this can be accomplished using something like Jetty's AsyncProxyServlet. You would basically need to set up your app container to pass requests with a certain path to your servlet ("service1" for example) and then in your servlet you would validate if the path the user was trying to hit was valid or whether it is an error (i.e. you probably don't want people proxying through your app to random services).
http://download.eclipse.org/jetty/9.3.11.v20160721/apidocs/org/eclipse/jetty/proxy/ProxyServlet.Transparent.html
I'm looking to return per request debug information in a JSON HTTP response body. This debug information would be collected throughout my application, including data such as DB queries and how long they took, external calls made, whether certain conditions were met, general messages showing application flow etc.
I've looked into Java logging frameworks and the Play Framework, which I am using, has a built in logger that works great for logging information to files. But I can't seem to find any that handle request level logging i.e. store debug messages for this particular HTTP request to be returned with this request and then destroyed.
I could of course create a Debug class, instantiate that and pass that around throughout my application for each request, but this doesn't seem like a nice way to handle this as I would need to be passing this into a lot of classes in my application.
Are there any better ways/design patterns/libraries out there that can do what I'm looking for without having to pass a Debug object round my entire application?
It is not a common usage, so I do not think that you will find a product implementing that. You have basically 2 possibilities :
fully implement a custom logger and use it throughout your application
use a well known local api (slf4j, apache commons logging) and implement a dedicated back-end
Either way, the backend part should :
initiate a buffer to collect logs at request reception (probably in a filter) and put it in a ThreadLocal variable
collects all logs during the request help to the ThreadLocal variable
release the ThreadLocal variable at the end of request (in same filter that allocates it)
And all servlets of controllers should be modified to add the logging content to the json response body.
I found a solution, the Play Framework provides request level storage for arbitrary objects using Http.Context.current().args I'm using this HashMap to store my custom debug storage class so that I can access it throughout a request anywhere in my application.
Instead of passing Debug object from layer to layer, why don't you use Http.Context? It is defined at Controller class:
public abstract class Controller extends Results implements Status, HeaderNames {
...
public static Context ctx() {
return Http.Context.current();
}
}
Usage:
ctx().args.put(key, value)
ctx().args.get(key);
You don't need to use a logging framework for it. The best approach to return your debug info in the json response is to use the same method you are using to return the rest of the json.
This way, you can setup it to work in debug mode via -Dsomevar=debug or via an HTTP request parameter like debug=true