Enable own metrics when all other are disabled - spring-micrometer

I would like to turn off all metrics except my own metrics.
I used the property for that. However, my own metrics were then also switched off.
management.metrics.enable.all=false
How can I turn it back on?
I've tried the following, unfortunately it doesn't work
management.metrics.enable.all=false
management.metrics.enable.my=true
Metrics.gauge( "my.metric.name", List.of("tag1","tag2"), value );

A slightly different way of allowing only yours metrics is to use a deny filter and only allow your custom metric to pass through. It will not disable other metrics but just denying them from being pushed or pulled.
Spring-Boot example:
#Configuration
public class MetricRegistryConfig {
#Bean
public MeterRegistryCustomizer<MeterRegistry> metricsRegistryConfig() {
return registry -> registry.config()
.meterFilter(MeterFilter
.deny(id -> !"my.metric.name".equals(id.getName())));
}
}

Related

How to get back MDC "inheritance" with modern logback?

After going back to an older project and getting around to update its dependencies I had to realize that logback does not anymore propagate MDCs to children since version 1.1.5: https://github.com/qos-ch/logback/commit/aa7d584ecdb1638bfc4c7223f4a5ff92d5ee6273
This change makes most of the logs nigh useless.
While I can understand the arguments given in the linked issues, I can not understand why this change could not have been made in a more backwards compatible manner (as is generally usual in java..).
Q: What is the now correct way to achieve the same behaviour other than having to subclass everything from Runnables to Threads?
I see no straightforward way to change this back. Two alternatives that come to mind are:
Way #1: Wrap all Runnables
Introduce an abstract class that will copy MDC from the original Thread to a new Thread and use it instead of Runnable
public abstract class MdcAwareRunnable implements Runnable
{
private Map<String, String> originalMdc;
public MdcAwareRunnable()
{
this.originalMdc = MDC.getCopyOfContextMap();
}
#Override
public void run()
{
MDC.setContextMap(originalMdc);
runImpl();
}
protected abstract void runImpl();
/**
* In case some Runnable comes from external API and we can't change that code we can wrap it anyway.
*/
public static MdcAwareRunnable wrap(Runnable runnable)
{
return new MdcAwareRunnable()
{
#Override
protected void runImpl()
{
runnable.run();
}
};
}
}
If some Runnable comes from an external API that you can't change that code, use wrap helper method.
Drawback: need to analyze and change whole code.
Way #2: Mess with slf4j internals
Resurrect the original LogbackMDCAdapter implementation that uses InheritableThreadLocal from before that commit and put it somewhere in your code under some other name. Then somewhere around startup use reflection to override MDC.mdcAdapter property with and instance of that custom implementation. This is obviously a dirty hack but it saves a lot of troubles comparing to #1.
Note: for performance reasons it makes to inherit your resurrected version from existing LogbackMDCAdapter and just override all the methods with old implementation. See LoggingEvent.java and LogbackMDCAdapter.getPropertyMap internal method for some details.
Way #3: Mess with logback jar (even stranger alternative)
This sounds to me as a quite bad plan but for completness here it is.
Again resurrect the original LogbackMDCAdapter but this time don't rename, compile it and override that .class file inside logback.jar.
Or resurrect the original LogbackMDCAdapter with renaming, remove .class file for org.slf4j.impl.StaticMDCBinder from logback.jar and add your own class that will return resurrected version of LogbackMDCAdapter either to logback.jar or to your code. MDC seems to be bound to that class by name to create an implementation of MDCAdapter to use.
Or you can achieve similar result by using custom ClassLoader that would map org.slf4j.impl.StaticMDCBinder to your class instead of the one inside logback.jar. Note: this is probably impossible to achieve inside a Web-container that will add its own custom ClassLoaders.
Way 4: Misuse TurboFilter
ch.qos.logback.classic.Logger passes the logging event to a filter before passing it along to the appenders.
Way 5: Modify log Encoder / provider
Although this would mean the logging event is not updated, but the log output will be.

Need to perform RequestBasedLogging

I have a need to implement request based logging.
Based on header - log-level-header.
In my code, I am using JAX-RS and have implemented ContainerRequestFilter.
#Override
public void filter(final ContainerRequestContext context) throws IOException {
String log_level = context.getHeaderString("log-level-header");
//translate to actual log level
Logger root = (Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
root.setLevel(logLevelToSet);
}
I am using Logback and slf4j API.
The problem is that i am setting the log level to the RootLogger which is a singleton and hence ends up modifying the log level across application.
Instead I intend to change the log level for a particular thread (RequestBasedLogging). Is it achievable and how?
Yes, this is achievable via TurboFilters and MDC. The code in MDCFilter should be helpful as well.
The key is to understand MDC.

INeedInitialization or IConfigureThisEndpoint, which one to use?

I know we can implement IWantCustomInitialization to configure NServicebus with other IoC continers lets say Castle.Windsor for instance, but I found this is obsoleted. in new version alternatively I used INeedInitialization, but it also didn't solve my issue because the container was specified before "INeedInitialization.Customize" invocation, So
at last I implemented IConfigureThisEndpoint as my final solution.
To sum up my question; when to use "INeedInitialization" and "IConfigureThisEndpoint"?
Best Regards
Both give you access to do basically the same things. The big difference is that IConfigureThisEndpoint is once per endpoint, so you use that to configure truly endpoint-specific things. INeedInitialization can have many implementations, and all of them get executed. So you can package up multiple INeedInitialization behaviors in a Conventions assembly and use them throughout your solution to carry out tasks common to multiple (or all) endpoints.
This has been changed a bit over time and v5 of NServiceBus introduce a different API. For context you can read through the following bug comments. What the intent is:
IConfigureThisEndpoint - for configuring the Endpoint. Can only have 1 per instance.
INeedInitialization - for configuring a component used by the Endpoint. Can have multiple implementations of this per instance.
An example of when to use IConfigureThisEndpoint (see full example)
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, UsingTransport<MsmqTransport>
{
public void Customize(BusConfiguration configuration)
{
configuration.UsePersistence<NHibernatePersistence>();
}
}
An example of when to use INeedInitialization (see full example)
class ResponderInstaller : INeedInitialization
{
public void Init()
{
Configure.Instance.Configurer.ConfigureComponent<CustomHttpResponder>(DependencyLifecycle.InstancePerCall);
}
}

MvvmCross: Turn off MvxTrace timestamps (PrependWithTime)

Looking for recommendations on how to override the default implementation of MvxTrace to disable the default behaviour of appending the time since application launch aka PrependWithTime:
https://github.com/MvvmCross/MvvmCross/blob/v3.1/CrossCore/Cirrious.CrossCore/Platform/MvxTrace.cs#L152
private static string PrependWithTime(string input)
{
var timeIntoApp = (DateTime.UtcNow - WhenTraceStartedUtc).TotalSeconds;
return string.Format("{0,6:0.00} {1}", timeIntoApp, input);
}
Looking at the code, I'd guess you can't easily override this behaviour.
If it's just text formatting you want to change, then you could remove the timestamps again afterwards in a custom IMvxTrace implementation injected during Setup.
However, if you wanted more customisation here, then you'd need to make some sort of change to Mvx - which you could do via a Feature Request or Pull Request in http://github.com/mvvmcross/mvvmcross/issues

How to log user operations in a web application?

The environment of my application: web-based, Spring MVC+Security, Hibernate, MySQL(InnoDB)
I am working on a small database application operated from a web interface. There are specific and known users that handle the stored data. Now I need to keep track of every create/update/delete action a user executes on the database and produce simple, "list-like" reports from this. As of now, I am thinking of a "log" table (columns: userId + timestamp + description etc.). I guess an aspect could be fired upon any C(R)UD operation inserting a log row in this table. But I am not sure this is how it should be done.
I am also aware of the usual MySQL logs as well as log4j. As for the logfiles, I might need more information than what is available to MySQL. Log4j might be a solution, but I do not see how it is able to write to MySQL tables. Also, I would like to have some associations preserved in my log table (e.g. the user id) to let the db do the basic filtering etc. Directions on this one appreciated.
What would you recommend? Is there even any built-in support in Hibernate/Spring or is log4j the right way to go?
Thanks!
Log4j is modular, you can write your own backend that writes the log into a database if you wish to do so; in fact, it even comes with a JDBC appender right out of box, although make note of the big red warning there.
For Hibernate, you probably can build something on the interceptors and events that keep track of all modifications and log them to a special audit table.
Have you looked into using a MappedSuperclass for C(R)UD operation logging?
#MappedSuperclass
public class BaseEntity {
#Basic
#Temporal(TemporalType.TIMESTAMP)
public Date getLastUpdate() { ... }
public String getLastUpdater() { ... }
...
}
#Entity class Order extends BaseEntity {
#Id public Integer getId() { ... }
...
}
In case you go for logging solution and looking for doing it yourself, try searching for JDBCAppender, it's not perfect but should work.
In case you want off the shelf product for centralized logging - consider trying logFaces - it can write directly into your own database (Disclosure: I am the author of this product.)