001package org.jpos.metrics.iso; 002 003import io.micrometer.core.instrument.MeterRegistry; 004import io.micrometer.core.instrument.Tags; 005import org.jpos.iso.ISOMsg; 006import org.jpos.metrics.MeterInfo; 007 008import java.util.ArrayList; 009import java.util.List; 010import java.util.stream.Collectors; 011 012/** Interface for ISO message metrics tracking. */ 013public interface ISOMsgMetrics { 014 /** Default channel metric name. */ 015 String DEFAULT_CHANNEL_METRIC_NAME = MeterInfo.ISOMSG_IN.id(); 016 017 /** Environment variable name for channel tags configuration. */ 018 String ENV_CHANNEL_TAGS = "metrics.channel.tags"; 019 /** Default tags for channel metrics. */ 020 String DEFAULT_TAGS = "name, type, direction"; 021 022 /** Environment variable name for channel fields configuration. */ 023 String ENV_CHANNEL_FIELDS = "metrics.channel.fields"; 024 /** Default channel fields for metrics. */ 025 String DEFAULT_CHANNEL_FIELDS = "mti"; 026 027 /** Implemented by components that expose an {@link ISOMsgMetrics} instance. */ 028 interface Source{ 029 /** 030 * Sets the ISOMsgMetrics instance. 031 * @param metrics the ISOMsgMetrics to attach 032 */ 033 void setISOMsgMetrics(ISOMsgMetrics metrics); 034 /** 035 * Returns the attached ISOMsgMetrics. 036 * @return the ISOMsgMetrics, or null 037 */ 038 ISOMsgMetrics getISOMsgMetrics(); 039 } 040 041 /** Sets the metric name. 042 * @param metricName the metric name 043 */ 044 void setMetricName(String metricName); 045 /** Returns the metric name. 046 * @return the metric name 047 */ 048 String getMetricName(); 049 050 /** Returns the metric description. 051 * @return the metric description 052 */ 053 String getMetricDescription(); 054 /** Sets the metric description. 055 * @param metricDescription the metric description 056 */ 057 void setMetricDescription(String metricDescription); 058 059 /** Adds metric tags to the given Tags object. 060 * @param tags the Tags to add to 061 * @return the updated Tags 062 */ 063 Tags addTags(Tags tags); 064 /** Adds metric tags from an array of strings. 065 * @param tags the tags to add 066 * @return the updated Tags 067 */ 068 default Tags addTags(String ...tags) { return addTags(Tags.of(tags)); } 069 /** Returns all metric tags. 070 * @return the metric tags 071 */ 072 default Tags getTags() { return addTags(Tags.empty()); } 073 074 /** 075 * Records an {@link ISOMsg} in the meter registry.<br> 076 * The metric name and tags will be taken strictly from this object's 077 * configuration. <br> 078 * If this object hasn't been successfully registered, it throws an 079 * {@link IllegalStateException}. 080 * 081 * @param m the {@link ISOMsg} to record. 082 * @throws IllegalStateException when this object hasn't been registered 083 */ 084 void recordMessage(ISOMsg m) throws IllegalStateException; 085 086 /** 087 * Records an {@link ISOMsg} in the meter registry.<br> 088 * Similar to {@link #recordMessage(ISOMsg)} but using the metric name, description and maybe some 089 * tags taken from the {@link MeterInfo} argument. 090 * <p> 091 * If the metric for that combination of {@link MeterInfo} values and local values fails to register 092 * in the global {@link MeterRegistry} (or any underlying one like the Prometheus registry), the method 093 * may throw an {@link IllegalStateException}. This also happens if this object hasn't been successfully 094 * registered by The metric name and tags will be taken from 095 * what has been configured. If this object hasn't been successfully registered, it throws an 096 * {@link IllegalStateException}. 097 * 098 * @param m the ISO message 099 * @param meterInfo the meter info to record 100 * @throws IllegalStateException if recording fails 101 */ 102 void recordMessage(ISOMsg m, MeterInfo meterInfo) throws IllegalStateException; 103 104 105 /** 106 * Register this object to work with a given {@link MeterRegistry}.<br> 107 * 108 * This method may serve more than one purpose in the object's lifecycle: 109 * <ul> 110 * <li>Assign a {@link MeterRegistry} to be used for the created meters. 111 * (The registry can be obtained by calling {@link #getRegistry()})</li> 112 * <li>Before this object has been registered, it can be configured by setting tags, etc., 113 * but attempting to record a message (e.g. through {@link #recordMessage(ISOMsg)}) 114 * will throw an {@link IllegalStateException}.</li> 115 * <li>After it has been registered, it's ready to record messages. 116 * However, it <b>can't be configured</b> any longer, or it will throw an {@link IllegalStateException}. 117 * The object's configuration can be considered "frozen".</li> 118 * <li>In some (future) implementation, it may make use of the {@link #getMetricSignature()} to 119 * do some caching to ensure that every metric name has only one set of tag keys, thus avoiding 120 * metrics name+keyset collision in {@code PrometheusMeterRegistry}.</li> 121 * </ul> 122 * 123 * The {@link #unregister()} method should be called when done using this object. 124 * 125 * @param registry the meter registry to register with 126 * @return true if successful, false if there was an error 127 */ 128 boolean register(MeterRegistry registry); 129 130 /** 131 * It calls {@link #removeMeters()} and clears its internal reference to its {@link MeterRegistry}.<br> 132 * 133 * It will also "unfreeze" the object, making it available for reconfiguration. 134 */ 135 void unregister(); 136 137 /** 138 * Returns the meter registry. 139 * @return the MeterRegistry 140 */ 141 MeterRegistry getRegistry(); 142 143 /** Removes all registered meters. */ 144 void removeMeters(); 145 146 147 /** 148 * A unique meter signature, concatenating the meter name, vertical pipe, comma-separated sorted list of all tag keys 149 * that this object produces.<br> 150 * Default implementation uses the values from {@link #getMetricName()} and {@link #getTags()}. 151 * A concrete implementation must make sure of gathering all the appropriate tag keys from internal config state 152 * which may include more than what's returned by {@link #getTags()}. 153 * @return The unique metric signature. 154 */ 155 default String getMetricSignature() { 156 List<String> keys = new ArrayList<>(); 157 getTags().forEach(t -> keys.add(t.getKey())); 158 return getMetricName()+"|"+ 159 keys.stream().sorted().collect(Collectors.joining(",")); 160 } 161}