Integrate Spring Boot Actuator with New Relic - spring-boot

I am trying to integrate New Relic with Spring Boot actuator. Most of the tutorials and response in StackOverflow itself suggest to use New Relic Java Agent but as per Spring Boot documentation installing Java Agent is not mandatory (unless I misunderstood something) also checked this. So, here is my application.properties currently.
management.metrics.export.newrelic.enabled = true
management.metrics.export.newrelic.api-key = <API_KEY>
management.metrics.export.newrelic.account-id = <ACCOUNT_ID>
logging.level.io.micrometer.newrelic=TRACE
management.metrics.export.newrelic.step=30s
and in the log I am seeing
2021-01-11 12:05:18.315 DEBUG 44635 --- [trics-publisher] i.m.n.NewRelicInsightsApiClientProvider : successfully sent 73 metrics to New Relic.
Based on this logs it looks like it is sending logs. But I have no idea where to see this logs. Ideally I would like to pass app name as well so that I can differentiate metric by app name and preferably by env as well later. Any suggestions?

To add "app name" and "env" to your metrics, you just need to configure the MeterFilter with the common tags:
#Configuration
public class MetricsConfig {
#Bean
public MeterFilter commonTagsMeterFilter(#Value("...") appName, #Value("...") env) {
return MeterFilter.commonTags(Tag.of("app name", appName), Tag.of("env", env);
}
}
Setting the following property you should be able to see what metrics are being sent to NewRelic:
logging.level.io.micrometer.newrelic=TRACE

Related

Configuration Bean in Quarkus

This is regarding CDI spec of quarkus. Would want to understand is there a configuration bean for quarkus? How does one do any sort of configuration in quarkus?
If I get it right the original question is about #Configuration classes that can contain #Bean definitions. If so then CDI producer methods and fields annotated with #javax.enterprise.inject.Produces are the corresponding alternative.
Application configuration is a completely different question though and Jay is right that the Quarkus configuration reference is the ultimate source of information ;-).
First of all reading how cdi spec of quarkus differs from spring is important.
Please refer this guide:
https://quarkus.io/guides/cdi-reference
The learnings from this guide is there is #Produces which is an alternative to #Configuration bean in Quarkus.
Let us take an example for libs that might require a configuration through code. Example: Microsoft Azure IOT Service Client.
public class IotHubConfiguration {
#ConfigProperty(name="iothub.device.connection.string")
String connectionString;
private static final Logger LOG = Logger.getLogger(IotHubConfiguration.class);
#Produces
public ServiceClient getIot() throws URISyntaxException, IOException {
LOG.info("Inside Service Client bean");
if(connectionString==null) {
LOG.info("Connection String is null");
throw new RuntimeException("IOT CONNECTION STRING IS NULL");
}
ServiceClient serviceClient = new ServiceClient(connectionString, IotHubServiceClientProtocol.AMQPS);
serviceClient.open();
LOG.info("opened Service Client Successfully");
return serviceClient;
}
For all libs vertically intergrated with quarkus application.properties can be used and then you will get a driver obj for that broker/dbs available directly through #Inject in your #applicationScoped/#Singleton bean So, Why is that?
To Simplify and Unify Configuration
To Make Sure no code is required for configuring anything i.e. database config, broker config , quarkus config etc.
This drastically reduces the amount of code written for configuring and also Junits needed to cover that code.
Let us take an example where kafka producer configuration needs to be added: in application.properties
kafka.bootstrap.servers=${KAFKA_BROKER_URL:localhost:9092}
mp.messaging.outgoing.incoming_kafka_topic_test.topic=${KAFKA_INPUT_TOPIC_FOR_IOT_HUB:input_topic1}
mp.messaging.outgoing.incoming_kafka_topic_test.connector=smallrye-kafka
mp.messaging.outgoing.incoming_kafka_topic_test.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
mp.messaging.outgoing.incoming_kafka_topic_test.key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
mp.messaging.outgoing.incoming_kafka_topic_test.health-readiness-enabled=true
For full blown project reference: https://github.com/JayGhiya/QuarkusExperiments/tree/initial_version_v1/KafkaProducerQuarkus
Quarkus References for Config:
https://quarkus.io/guides/config-reference
Example for reactive sql config: https://quarkus.io/guides/reactive-sql-clients
Now let us talk about a bonus feature that quarkus provides which improves developer experience by atleast an order of magnitude that is profile driven development and testing.
Quarkus provides three profiles:
dev - Activated when in development mode (i.e. quarkus:dev)
test - Activated when running tests
prod - The default profile when not running in development or test
mode
Let us just say that in the given example you wanted to have different topics for development and different topics for production. Let us achieve that!
%dev.mp.messaging.outgoing.incoming_kafka_topic_test.topic=${KAFKA_INPUT_TOPIC_FOR_IOT_HUB:input_topic1}
%prod.mp.messaging.outgoing.incoming_kafka_topic_test.topic=${KAFKA_INPUT_TOPIC_FOR_IOT_HUB:prod_topic}
This is how simple it is. This is extremely useful in cases where your deployments run with ssl enabled brokers/dbs etc and for dev purposes you have unsecure local brokers/dbs. This is a game changer.

ElasticsearchJestHealthIndicator : Health check failed when using Jest in spring boot

I'm using Jest at enter link description here in my spring boot application.
Then I created the client with the example code :
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(new HttpClientConfig
.Builder("http://myhost:9200")
.multiThreaded(true)
JestClient client = factory.getObject();
Everything is fine. I can use this client to do all the queries I want. Happy till now.
Then the problem, when the application starts up, ElasticsearchJestHealthIndicator class is auto-initialized. But the problem is I don't know where to set the config that it will need, so it uses the default value as http://localhost:9200, which leads me to this problem:
WARN [on(2)-127.0.0.1] s.b.a.h.ElasticsearchJestHealthIndicator : Health check failed
io.searchbox.client.config.exception.CouldNotConnectException: Could not connect to http://localhost:9200
at io.searchbox.client.http.JestHttpClient.execute(JestHttpClient.java:70)
at io.searchbox.client.http.JestHttpClient.execute(JestHttpClient.java:60)
Can someone show me how to properly config it , or turn it off ?
A quick search in the reference documentation shows that Spring Boot will configure for you a JestClient (you can just inject it anywhere you need), and that the following configuration properties apply:
spring.elasticsearch.jest.uris=http://search.example.com:9200
spring.elasticsearch.jest.read-timeout=10000
spring.elasticsearch.jest.username=user
spring.elasticsearch.jest.password=secret
See here for more on this.
The Jest client has been deprecated as well, since both Elasticsearch and Spring Data Elasticsearch provide official support for REST clients.
See https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-elasticsearch

Spring Boot 2 integrate Brave MySQL-Integration into Zipkin

I am trying to integrate the Brave MySql Instrumentation into my Spring Boot 2.x service to automatically let its interceptor enrich my traces with spans concerning MySql-Queries.
The current Gradle-Dependencies are the following
compile 'io.zipkin.zipkin2:zipkin:2.4.5'
compile('io.zipkin.reporter2:zipkin-sender-okhttp3:2.3.1')
compile('io.zipkin.brave:brave-instrumentation-mysql:4.14.3')
compile('org.springframework.cloud:spring-cloud-starter-zipkin:2.0.0.M5')
I already configured Sleuth successfully to send traces concerning HTTP-Request to my Zipkin-Server and now I wanted to add some spans for each MySql-Query the service does.
The TracingConfiguration it this:
#Configuration
public class TracingConfiguration {
/** Configuration for how to send spans to Zipkin */
#Bean
Sender sender() {
return OkHttpSender.create("https://myzipkinserver.com/api/v2/spans");
}
/** Configuration for how to buffer spans into messages for Zipkin */
#Bean AsyncReporter<Span> spanReporter() {
return AsyncReporter.create(sender());
}
#Bean Tracing tracing(Reporter<Span> spanListener) {
return Tracing.newBuilder()
.spanReporter(spanReporter())
.build();
}
}
The Query-Interceptor works properly, but my problem now is that the spans are not added to the existing trace but each are added to a new one.
I guess its because of the creation of a new sender/reporter in the configuration, but I have not been able to reuse the existing one created by the Spring Boot Autoconfiguration.
That would moreover remove the necessity to redundantly define the Zipkin-Url (because it is already defined for Zipkin in my application.yml).
I already tried autowiring the Zipkin-Reporter to my Bean, but all I got is a SpanReporter - but the Brave-Tracer-Builder requries a Reporter<Span>
Do you have any advice for me how to properly wire things up?
Please use latest snapshots. Sleuth in latest snapshots uses brave internally so integration will be extremely simple.

Spring Boot Actuator paths not enabled by default?

While updating my Spring Boot application to the latest build snapshot and I am seeing that none of the actuator endpoints are enabled by default. If I specify them to be enabled in application.properties, they show up.
1) Is this behavior intended? I tried searching for an issue to explain it but couldn't find one. Could somebody link me to the issue / documentation?
2) Is there a way to enable all the actuator endpoints? I often find myself using them during development and would rather not maintain a list of them inside my properties file.
Two parts to this answer:
"Is there a way to enable all the actuator endpoints?"
Add this property endpoints.enabled=true rather than enabling them individually with endpoints.info.enabled=true, endpoints.beans.enabled=true etc
Update: for Spring Boot 2.x the relevant property is:
endpoints.default.web.enabled=true
"Is this behavior intended?"
Probably not. Sounds like you might have spotted an issue with the latest milestone. If you have a reproducible issue with a Spring Boot milestone then Spring's advice is ...
Reporting Issues
Spring Boot uses GitHub’s integrated issue tracking system to record bugs and feature requests. If you want to raise an issue, please follow the recommendations below:
Before you log a bug, please search the issue tracker to see if someone has already reported the problem.
If the issue doesn’t already exist, create a new issue.
Even if we enable all the actuator endpoints as below
management.endpoints.web.exposure.include=* (In case of YAML the star character should be surrounded by double quotes as "*" because star is one of the special characters in YAML syntax)
The httptrace actuator endpoint will still not be enabled in web by default. HttpTraceRepository interface need to be implemented to enable httptrace (See Actuator default endpoints, Actuator endpoints, Actuator httptrace).
#Component
public class CustomHttpTraceRepository implements HttpTraceRepository {
AtomicReference<HttpTrace> lastTrace = new AtomicReference<>();
#Override
public List<HttpTrace> findAll() {
return Collections.singletonList(lastTrace.get());
}
#Override
public void add(HttpTrace trace) {
if ("GET".equals(trace.getRequest().getMethod())) {
lastTrace.set(trace);
}
}
}
Now the endpoints can be accessed using the url,
http://localhost:port/actuator/respective-actuator-endpoint
(Example http://localhost:8081/actuator/httptrace)
If there is a management.servlet.context-path value present in properties file then the URL will be,
http://localhost:port/<servlet-context-path>/respective-actuator-endpoint
(Example http://localhost:8081/management-servlet-context-path-value/httptrace)
UPDATE: use this only in dev environment, not in production!
Is there a way to enable all the actuator endpoints?
Using Spring Boot 2.2.2 Release, this worked for me:
On the file src/main/resources/application.properties add this:
management.endpoints.web.exposure.include=*
To check enabled endpoints go to http://localhost:8080/actuator
Source: docs.spring.io

Reload property value when external property file changes ,spring boot

I am using spring boot, and I have two external properties files, so that I can easily change its value.
But I hope spring app will reload the changed value when it is updated, just like reading from files. Since property file is easy enough to meet my need, I hope I don' nessarily need a db or file.
I use two different ways to load property value, code sample will like:
#RestController
public class Prop1Controller{
#Value("${prop1}")
private String prop1;
#RequestMapping(value="/prop1",method = RequestMethod.GET)
public String getProp() {
return prop1;
}
}
#RestController
public class Prop2Controller{
#Autowired
private Environment env;
#RequestMapping(value="/prop2/{sysId}",method = RequestMethod.GET)
public String prop2(#PathVariable String sysId) {
return env.getProperty("prop2."+sysId);
}
}
I will boot my application with
-Dspring.config.location=conf/my.properties
I'm afraid you will need to restart Spring context.
I think the only way to achieve your need is to enable spring-cloud. There is a refresh endpoint /refresh which refreshes the context and beans.
I'm not quite sure if you need a spring-cloud-config-server (its a microservice and very easy to build) where your config is stored(Git or svn). Or if its also useable just by the application.properties file in the application.
Here you can find the doc to the refresh scope and spring cloud.
You should be able to use Spring Cloud for that
Add this as a dependency
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.2.RELEASE'
And then use #RefreshScope annotation
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
Also relevant if you have Spring Actuator
For a Spring Boot Actuator application there are some additional management endpoints:
POST to
/env to update the Environment and rebind #ConfigurationProperties and log levels
/refresh for re-loading the boot strap context and refreshing the #RefreshScope beans
Spring Cloud Doc
(1) Spring Cloud's RestartEndPoint
You may use the RestartEndPoint: Programatically restart Spring Boot application / Refresh Spring Context
RestartEndPoint is an Actuator EndPoint, bundled with spring-cloud-context.
However, RestartEndPoint will not monitor for file changes, you'll have to handle that yourself.
(2) devtools
I don't know if this is for a production application or not. You may hack devtools a little to do what you want.
Take a look at this other answer I wrote for another question: Force enable spring-boot DevTools when running Jar
Devtools monitors for file changes:
Applications that use spring-boot-devtools will automatically restart
whenever files on the classpath change.
Technically, devtools is built to only work within an IDE. With the hack, it also works when launched from a jar. However, I may not do that for a real production application, you decide if it fits your needs.
I know this is a old thread, but it will help someone in future.
You can use a scheduler to periodically refresh properties.
//MyApplication.java
#EnableScheduling
//application.properties
management.endpoint.refresh.enabled = true
//ContextRefreshConfig.java
#Autowired
private RefreshEndpoint refreshEndpoint;
#Scheduled(fixedDelay = 60000, initialDelay = 10000)
public Collection<String> refreshContext() {
final Collection<String> properties = refreshEndpoint.refresh();
LOGGER.log(Level.INFO, "Refreshed Properties {0}", properties);
return properties;
}
//add spring-cloud-starter to the pom file.
Attribues annotated with #Value is refreshed if the bean is annotated with #RefreshScope.
Configurations annotated with #ConfigurationProperties is refreshed without #RefreshScope.
Hope this will help.
You can follow the ContextRefresher.refresh() code implements.
public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}

Resources