Class MatsMicrometerInterceptor

  • All Implemented Interfaces:
    io.mats3.api.intercept.MatsInitiateInterceptor, io.mats3.api.intercept.MatsMetricsInterceptor, io.mats3.api.intercept.MatsStageInterceptor, io.mats3.MatsFactory.MatsPlugin

    public class MatsMicrometerInterceptor
    extends java.lang.Object
    implements io.mats3.api.intercept.MatsMetricsInterceptor, io.mats3.api.intercept.MatsInitiateInterceptor, io.mats3.api.intercept.MatsStageInterceptor
    An interceptor that instruments a MatsFactory with metrics using the (Spring) Micrometer framework. If you provide a MeterRegistry, it will employ this to create the metrics on, otherwise it employs the Metrics.globalRegistry.

    Meters included are for these different phases:

    1. Initiate Completed
    2. Message Received (on Stage)
    3. Stage Completed

    Metrics being recorded

    These are the 11 default + user metrics being recorded as Micrometer Timers or DistributionSummarys - Remember that counts are also implicitly present:

    Execution: Init or stage:

    • Timing: "mats.exec.total" Total time taken to execute init or stage.
    • Timing: "mats.exec.userlambda" Part of total exec time taken for the actual user lambda itself from start to finish, which thus includes any external IO like e.g. DB or HTTP calls the user code performs, minus any time taken to construct outbound Mats messages. Any use 'ctx.log[Timing]Measurement(..)' within user lambda, to break out e.g. metrics for any potentially expensive IO, is available as 'mats.exec.ops.time.' and 'mats.exec.ops.measure.' metrics."
    • Timing: "mats.exec.out" Part of total exec time taken to produce and send messages: Produce, serialize and compress all DTOs, STOs and message envelopes, and produce and send all system messages.
    • Quantity: "mats.exec.out.quantity" Number of outgoing messages from execution.
    • Timing: "mats.exec.db.commit" Part of total time taken to commit database.
    • Timing: "mats.exec.msgsys.commit" Part of total time taken to commit message system.
    • Timing: "mats.exec.ops.time." If user adds timings, it will be added as a metric with this prefix.
    • Measure: "mats.exec.ops.measure." If user adds measurements, it will be added as a metric with this prefix.
    Receive:
    • Timing: "mats.in.total" Total time taken to preprocess and deserialize incoming message.
    Message sent:
    • Timing: "mats.out.total" Total time taken to produce, serialize and compress DTO, STO and message envelope, and produce and send system message
    • Timing: "mats.out.msgsys" From out total, time taken to produce and send message.
    • Size: "mats.out.envelope" Outgoing mats envelope full size.
    • Size: "mats.out.wire" Outgoing mats envelope wire size.

    Tags on meters

    Meters will have the following tags (which can be used to filter the series on):
    • "appName" AppName for "this" service.
    • "appVersion" AppVersion for "this" service.
    • "exec" Whether "init" or "stage"
    • "initiatingAppName" AppName of the service which initiated the Mats Flow
    • "initiatorId" Which initiatorId initiated this Mats Flow
    • "initOrStageId" Used for both InitiatorId or StageId - "this" initiatorId (for inits) or stageId (for stages).
    • "stageIndex" For stages, return the stage index, i.e. "0" for initial stage, "1" for stage1, etc. Reads "" (empty string) for initiations.
    • "type" (Only for message metrics, both sent and received) the MatsOutgoingMessage.MessageType for the incoming/outgoing message.
    • "from" (Only for received messages) from which initiatorId or stageId the message came.
    • "to" (Only for sent messages) which stageId this message is targeting.

    Note: Number of produced meters: Notice the argument 'includeAllTags' on the multi-arg install(..) method (default false): If this is true, then tags will be added to the meters which will give higher semantic resolution and more information, but which might result in a quite substantial number of time series - if you have a popular Mats endpoint with many stages targeted by many other services (thus getting many differing 'from', 'initiatingAppName' and 'initiatorId'), you may get a "cardinality explosion", in particular if you also configure histograms. It is thus false by default, i.e. when using the single-arg install(..) method.
    Which extra tags are omitted in which situations when 'includeAllTags' is false:

    • Received (incoming message): "from" (from which initId or stageId) for initial stage, "initiatingAppName" and "initiatorId".
    • Stage execution: "initiatingAppName" and "initiatorId".
    • Stage outgoing messages: "to" (to which stage) for REPLY-messages (as that will have same cardinality as 'from'), "initiatingAppName" and "initiatorId".
    This arguably reduces the ability to deduce useful information from metrics quite a bit, since you then cannot glean which app/initiatorId results in e.g. the most messages for a specific endpoint or stage. This is an effect of Mats3's ability to let an Endpoint be employed generically by a multitude of other endpoints, i.e. like a given HTTP Endpoint can be used by a multitude of users. The direct comparison would be that you created a different meter for each user of a given HTTP endpoint. For a popular endpoint with many users, this would result in a massive number of different meters.

    You may set 'includeAllTags' to true, and then use a Micrometer MeterFilter to tweak the tags with more precision than this all-or-nothing approach, e.g. include "initiatingAppName" and "initiatorId" for specific endpoints or stages.

    This is not the case with the 'mats-intercept-logging' plugin, as that records all such meta info (and quite a bit more) on each log line. You can thus "after the fact" decide on what slicing you want the measures to be divided along. The negative is that this requires quite substantial amount of storage.

    Notice the class MatsMicrometerInterceptor.SuggestedTimingHistogramsMeterFilter, which configures the timing-specific metrics with hopefully relevant histograms. You may apply this as such:
    Metrics.globalRegistry.config().meterFilter(new SuggestedTimingHistogramsMeterFilter());
    .. or you may apply any other distribution or histogram configuration using the MeterFilter logic of Micrometer.

    Note: This interceptor (Micrometer Metrics) has special support in JmsMatsFactory: If present on the classpath, it is automatically installed using the install(MatsFactory) install method. This implies that it employs the Micrometer 'globalRegistry' - and 'includeAllTags' will be false. If you rather want to supply a specific registry, or change the 'includeAllTags' boolean value, then create and install a specific instance of this class using the install(MatsFactory, MeterRegistry, boolean) method - the JmsMatsFactory will then remove the automatically installed, since it implements the special marker-interface MatsMetricsInterceptor of which there can only be one instance installed. (In a Spring context where the MatsFactory is created for you using an annotation, you are still able to do this during early phases of Spring initialization: E.g. inject a reference to the MatsInterceptable (the MatsFactory) and just install the new instance. This is possible since the Micrometer meters are lazily created when initiations are performed and Mats Stages receives messages. The decision of which tags are in use is therefore not needed until right before the service becomes operational, that is, performs inits and receives messages.)

    See Also:
    MatsMicrometerInterceptor.SuggestedTimingHistogramsMeterFilter
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      static class  MatsMicrometerInterceptor.SuggestedTimingHistogramsMeterFilter
      A MeterFilter that applies a hopefully reasonable histogram to all Timer meters.
      • Nested classes/interfaces inherited from interface io.mats3.api.intercept.MatsInitiateInterceptor

        io.mats3.api.intercept.MatsInitiateInterceptor.InitiateCompletedContext, io.mats3.api.intercept.MatsInitiateInterceptor.InitiateInterceptContext, io.mats3.api.intercept.MatsInitiateInterceptor.InitiateInterceptOutgoingMessagesContext, io.mats3.api.intercept.MatsInitiateInterceptor.InitiateInterceptUserLambdaContext, io.mats3.api.intercept.MatsInitiateInterceptor.InitiateStartedContext, io.mats3.api.intercept.MatsInitiateInterceptor.MatsInitiateInterceptOutgoingMessages, io.mats3.api.intercept.MatsInitiateInterceptor.MatsInitiateInterceptUserLambda
      • Nested classes/interfaces inherited from interface io.mats3.api.intercept.MatsStageInterceptor

        io.mats3.api.intercept.MatsStageInterceptor.MatsStageInterceptOutgoingMessages, io.mats3.api.intercept.MatsStageInterceptor.MatsStageInterceptUserLambda, io.mats3.api.intercept.MatsStageInterceptor.StageCommonContext, io.mats3.api.intercept.MatsStageInterceptor.StageCompletedContext, io.mats3.api.intercept.MatsStageInterceptor.StageInterceptContext, io.mats3.api.intercept.MatsStageInterceptor.StageInterceptOutgoingMessageContext, io.mats3.api.intercept.MatsStageInterceptor.StageInterceptUserLambdaContext, io.mats3.api.intercept.MatsStageInterceptor.StagePreprocessAndDeserializeErrorContext, io.mats3.api.intercept.MatsStageInterceptor.StageReceivedContext
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      void initiateCompleted​(io.mats3.api.intercept.MatsInitiateInterceptor.InitiateCompletedContext ctx)  
      static MatsMicrometerInterceptor install​(io.mats3.MatsFactory matsFactory)
      Creates a MatsMicrometerInterceptor employing the provided globalRegistry, and installs it as a singleton on the provided MatsFactory
      static MatsMicrometerInterceptor install​(io.mats3.MatsFactory matsFactory, io.micrometer.core.instrument.MeterRegistry meterRegistry, boolean includeAllTags)
      Creates a MatsMicrometerInterceptor employing the provided MeterRegistry, and installs it as a singleton on the provided MatsFactory
      void stageCompleted​(io.mats3.api.intercept.MatsStageInterceptor.StageCompletedContext ctx)  
      void stageReceived​(io.mats3.api.intercept.MatsStageInterceptor.StageReceivedContext ctx)  
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • Methods inherited from interface io.mats3.MatsFactory.MatsPlugin

        addingEndpoint, addingInitiator, preStop, removedEndpoint, start, stop
      • Methods inherited from interface io.mats3.api.intercept.MatsInitiateInterceptor

        initiateStarted
      • Methods inherited from interface io.mats3.api.intercept.MatsStageInterceptor

        stageCompletedNextDirect, stagePreprocessAndDeserializeError
    • Field Detail

      • TIMER_EXEC_TOTAL_NAME

        public static final java.lang.String TIMER_EXEC_TOTAL_NAME
        See Also:
        Constant Field Values
      • TIMER_EXEC_TOTAL_DESC

        public static final java.lang.String TIMER_EXEC_TOTAL_DESC
        See Also:
        Constant Field Values
      • TIMER_EXEC_USER_LAMBDA_NAME

        public static final java.lang.String TIMER_EXEC_USER_LAMBDA_NAME
        See Also:
        Constant Field Values
      • TIMER_EXEC_USER_LAMBDA_DESC

        public static final java.lang.String TIMER_EXEC_USER_LAMBDA_DESC
        See Also:
        Constant Field Values
      • TIMER_EXEC_OUT_NAME

        public static final java.lang.String TIMER_EXEC_OUT_NAME
        See Also:
        Constant Field Values
      • TIMER_EXEC_OUT_DESC

        public static final java.lang.String TIMER_EXEC_OUT_DESC
        See Also:
        Constant Field Values
      • QUANTITY_EXEC_OUT_NAME

        public static final java.lang.String QUANTITY_EXEC_OUT_NAME
        See Also:
        Constant Field Values
      • QUANTITY_EXEC_OUT_DESC

        public static final java.lang.String QUANTITY_EXEC_OUT_DESC
        See Also:
        Constant Field Values
      • TIMER_EXEC_DB_COMMIT_NAME

        public static final java.lang.String TIMER_EXEC_DB_COMMIT_NAME
        See Also:
        Constant Field Values
      • TIMER_EXEC_DB_COMMIT_DESC

        public static final java.lang.String TIMER_EXEC_DB_COMMIT_DESC
        See Also:
        Constant Field Values
      • TIMER_EXEC_MSGSYS_COMMIT_NAME

        public static final java.lang.String TIMER_EXEC_MSGSYS_COMMIT_NAME
        See Also:
        Constant Field Values
      • TIMER_EXEC_MSGSYS_COMMIT_DESC

        public static final java.lang.String TIMER_EXEC_MSGSYS_COMMIT_DESC
        See Also:
        Constant Field Values
      • TIMER_EXEC_OPS_PREFIX

        public static final java.lang.String TIMER_EXEC_OPS_PREFIX
        See Also:
        Constant Field Values
      • MEASURE_EXEC_OPS_PREFIX

        public static final java.lang.String MEASURE_EXEC_OPS_PREFIX
        See Also:
        Constant Field Values
      • TIMER_IN_TOTAL_NAME

        public static final java.lang.String TIMER_IN_TOTAL_NAME
        See Also:
        Constant Field Values
      • TIMER_IN_TOTAL_DESC

        public static final java.lang.String TIMER_IN_TOTAL_DESC
        See Also:
        Constant Field Values
      • TIMER_OUT_TOTAL_NAME

        public static final java.lang.String TIMER_OUT_TOTAL_NAME
        See Also:
        Constant Field Values
      • TIMER_OUT_TOTAL_DESC

        public static final java.lang.String TIMER_OUT_TOTAL_DESC
        See Also:
        Constant Field Values
      • TIMER_OUT_MSGSYS_SEND_NAME

        public static final java.lang.String TIMER_OUT_MSGSYS_SEND_NAME
        See Also:
        Constant Field Values
      • TIMER_OUT_MSGSYS_SEND_DESC

        public static final java.lang.String TIMER_OUT_MSGSYS_SEND_DESC
        See Also:
        Constant Field Values
      • SIZE_OUT_ENVELOPE_NAME

        public static final java.lang.String SIZE_OUT_ENVELOPE_NAME
        See Also:
        Constant Field Values
      • SIZE_OUT_ENVELOPE_DESC

        public static final java.lang.String SIZE_OUT_ENVELOPE_DESC
        See Also:
        Constant Field Values
      • SIZE_OUT_WIRE_NAME

        public static final java.lang.String SIZE_OUT_WIRE_NAME
        See Also:
        Constant Field Values
      • SIZE_OUT_WIRE_DESC

        public static final java.lang.String SIZE_OUT_WIRE_DESC
        See Also:
        Constant Field Values
      • TAG_INITIATING_APP_NAME

        public static final java.lang.String TAG_INITIATING_APP_NAME
        See Also:
        Constant Field Values
      • TAG_INITIATOR_ID

        public static final java.lang.String TAG_INITIATOR_ID
        See Also:
        Constant Field Values
      • TAG_INIT_OR_STAGE_ID

        public static final java.lang.String TAG_INIT_OR_STAGE_ID
        See Also:
        Constant Field Values
      • MAX_NUMBER_OF_METRICS

        public static final int MAX_NUMBER_OF_METRICS
        This is a cardinality-explosion-avoidance limit in case of wrongly used initiatorIds. These are not supposed to be dynamic, but there is nothing hindering a user from creating a new initiatorId per initiation. Thus, if we go above a certain number of such entries, we stop adding.

        Value is 200.

        See Also:
        Constant Field Values
    • Method Detail

      • install

        public static MatsMicrometerInterceptor install​(io.mats3.MatsFactory matsFactory,
                                                        io.micrometer.core.instrument.MeterRegistry meterRegistry,
                                                        boolean includeAllTags)
        Creates a MatsMicrometerInterceptor employing the provided MeterRegistry, and installs it as a singleton on the provided MatsFactory
        Parameters:
        matsFactory - the MatsFactory to install on (probably a MatsFactory.
        meterRegistry - the Micrometer MeterRegistry to create meters on.
        includeAllTags - whether all tags should be included (which may easily result in very many time series) or not.
        Returns:
        the MatsMicrometerInterceptor instance which was installed as singleton.
      • install

        public static MatsMicrometerInterceptor install​(io.mats3.MatsFactory matsFactory)
        Creates a MatsMicrometerInterceptor employing the provided globalRegistry, and installs it as a singleton on the provided MatsFactory
        Parameters:
        matsFactory - the MatsFactory to install on (probably a MatsFactory.
        Returns:
        the MatsMicrometerInterceptor instance which was installed as singleton.
      • initiateCompleted

        public void initiateCompleted​(io.mats3.api.intercept.MatsInitiateInterceptor.InitiateCompletedContext ctx)
        Specified by:
        initiateCompleted in interface io.mats3.api.intercept.MatsInitiateInterceptor
      • stageReceived

        public void stageReceived​(io.mats3.api.intercept.MatsStageInterceptor.StageReceivedContext ctx)
        Specified by:
        stageReceived in interface io.mats3.api.intercept.MatsStageInterceptor
      • stageCompleted

        public void stageCompleted​(io.mats3.api.intercept.MatsStageInterceptor.StageCompletedContext ctx)
        Specified by:
        stageCompleted in interface io.mats3.api.intercept.MatsStageInterceptor