Add metrics for payout limits (#7)

This commit is contained in:
Egor Cherniak 2023-09-08 14:07:56 +03:00 committed by GitHub
parent c705972006
commit 62c40a4edf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 137 additions and 24 deletions

View File

@ -10,12 +10,22 @@ import java.util.concurrent.ConcurrentHashMap;
public class StorageConfig { public class StorageConfig {
@Bean @Bean
public Map<String, Double> limitsBoundaryAggregatesMap() { public Map<String, Double> paymentlimitsBoundaryAggregatesMap() {
return new ConcurrentHashMap<>(); return new ConcurrentHashMap<>();
} }
@Bean @Bean
public Map<String, Double> limitsAmountAggregatesMap() { public Map<String, Double> paymentlimitsAmountAggregatesMap() {
return new ConcurrentHashMap<>();
}
@Bean
public Map<String, Double> payoutlimitsBoundaryAggregatesMap() {
return new ConcurrentHashMap<>();
}
@Bean
public Map<String, Double> payoutlimitsAmountAggregatesMap() {
return new ConcurrentHashMap<>(); return new ConcurrentHashMap<>();
} }
} }

View File

@ -0,0 +1,8 @@
package dev.vality.exporter.limits.error;
public class UnknownLimitTypeException extends RuntimeException {
public UnknownLimitTypeException(String message) {
super(message);
}
}

View File

@ -9,6 +9,7 @@ public class CustomTag {
public static final String PROVIDER_ID_TAG = "provider_id"; public static final String PROVIDER_ID_TAG = "provider_id";
public static final String TERMINAL_ID_TAG = "terminal_id"; public static final String TERMINAL_ID_TAG = "terminal_id";
public static final String SHOP_ID_TAG = "shop_id"; public static final String SHOP_ID_TAG = "shop_id";
public static final String WALLET_ID_TAG = "wallet_id";
public static final String CURRENCY_TAG = "currency"; public static final String CURRENCY_TAG = "currency";
public static final String CONFIG_ID_TAG = "config_id"; public static final String CONFIG_ID_TAG = "config_id";
public static final String TIME_RANGE_TYPE = "time_range_type"; public static final String TIME_RANGE_TYPE = "time_range_type";
@ -31,6 +32,10 @@ public class CustomTag {
return Tag.of(SHOP_ID_TAG, shopId); return Tag.of(SHOP_ID_TAG, shopId);
} }
public static Tag walletId(String walletId) {
return Tag.of(WALLET_ID_TAG, walletId);
}
public static Tag currency(String currency) { public static Tag currency(String currency) {
return Tag.of(CURRENCY_TAG, currency); return Tag.of(CURRENCY_TAG, currency);
} }

View File

@ -0,0 +1,6 @@
package dev.vality.exporter.limits.model;
public enum LimitType {
PAYMENT,
PAYOUT
}

View File

@ -50,6 +50,8 @@ public class LimitsData {
@JsonProperty("party_id") @JsonProperty("party_id")
private String partyId; private String partyId;
private Route route; private Route route;
@JsonProperty("wallet_id")
private String walletId;
@JsonProperty("shop_id") @JsonProperty("shop_id")
private String shopId; private String shopId;

View File

@ -6,12 +6,19 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public enum Metric { public enum Metric {
CALENDAR_LIMITS_BOUNDARY( CALENDAR_PAYMENT_LIMITS_BOUNDARY(
formatWithPrefix("limits_boundary_by_calendar"), formatWithPrefix("payment_limits_boundary_by_calendar"),
"Calendar limits boundary since last scrape"), "Calendar payment limits boundary since last scrape"),
CALENDAR_LIMITS_AMOUNT( CALENDAR_PAYMENT_LIMITS_AMOUNT(
formatWithPrefix("limits_amount_by_calendar"), formatWithPrefix("payment_limits_amount_by_calendar"),
"Calendar limits amount since last scrape"); "Calendar payment limits amount since last scrape"),
CALENDAR_PAYOUT_LIMITS_BOUNDARY(
formatWithPrefix("payout_limits_boundary_by_calendar"),
"Calendar payout limits boundary since last scrape"),
CALENDAR_PAYOUT_LIMITS_AMOUNT(
formatWithPrefix("payout_limits_amount_by_calendar"),
"Calendar payout limits amount since last scrape");
@Getter @Getter
private final String name; private final String name;

View File

@ -4,7 +4,9 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import dev.vality.exporter.limits.entity.LimitConfigEntity; import dev.vality.exporter.limits.entity.LimitConfigEntity;
import dev.vality.exporter.limits.entity.TimeRangeType; import dev.vality.exporter.limits.entity.TimeRangeType;
import dev.vality.exporter.limits.error.UnknownLimitTypeException;
import dev.vality.exporter.limits.model.CustomTag; import dev.vality.exporter.limits.model.CustomTag;
import dev.vality.exporter.limits.model.LimitType;
import dev.vality.exporter.limits.model.LimitsData; import dev.vality.exporter.limits.model.LimitsData;
import dev.vality.exporter.limits.model.Metric; import dev.vality.exporter.limits.model.Metric;
import dev.vality.exporter.limits.repository.LimitConfigRepository; import dev.vality.exporter.limits.repository.LimitConfigRepository;
@ -14,6 +16,7 @@ import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@ -28,8 +31,10 @@ import java.util.stream.Collectors;
public class LimitsService { public class LimitsService {
private final MeterRegistryService meterRegistryService; private final MeterRegistryService meterRegistryService;
private final Map<String, Double> limitsBoundaryAggregatesMap; private final Map<String, Double> paymentLimitsBoundaryAggregatesMap;
private final Map<String, Double> limitsAmountAggregatesMap; private final Map<String, Double> paymentLimitsAmountAggregatesMap;
private final Map<String, Double> payoutLimitsBoundaryAggregatesMap;
private final Map<String, Double> payoutLimitsAmountAggregatesMap;
private final OpenSearchService openSearchService; private final OpenSearchService openSearchService;
private final LimitConfigRepository limitConfigRepository; private final LimitConfigRepository limitConfigRepository;
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
@ -57,17 +62,47 @@ public class LimitsService {
log.warn("limitConfigEntity null, no gauge limitsData {}", limitsData); log.warn("limitConfigEntity null, no gauge limitsData {}", limitsData);
break; break;
} }
var id = String.format(
"%s.%s.%s.%s.%s", var limitType = getLimitType(limitsData);
limitsData.getLimit().getConfigId(), switch (limitType) {
limitsData.getLimit().getRoute().getProviderId(), case PAYMENT -> {
limitsData.getLimit().getRoute().getTerminalId(), var id = String.format(
limitsData.getLimit().getShopId(), "%s.%s.%s.%s.%s",
limitsData.getLimit().getChange().getCurrency()); limitsData.getLimit().getConfigId(),
gauge(limitsBoundaryAggregatesMap, Metric.CALENDAR_LIMITS_BOUNDARY, id, getTags(limitsData, limitConfigEntity), limitsData.getLimit().getBoundary()); limitsData.getLimit().getRoute().getProviderId(),
gauge(limitsAmountAggregatesMap, Metric.CALENDAR_LIMITS_AMOUNT, id, getTags(limitsData, limitConfigEntity), limitsData.getLimit().getAmount()); limitsData.getLimit().getRoute().getTerminalId(),
limitsData.getLimit().getShopId(),
limitsData.getLimit().getChange().getCurrency());
gauge(paymentLimitsBoundaryAggregatesMap, Metric.CALENDAR_PAYMENT_LIMITS_BOUNDARY, id,
getPaymentLimitTags(limitsData, limitConfigEntity),
limitsData.getLimit().getBoundary());
gauge(paymentLimitsAmountAggregatesMap, Metric.CALENDAR_PAYMENT_LIMITS_AMOUNT, id,
getPaymentLimitTags(limitsData,
limitConfigEntity), limitsData.getLimit().getAmount());
}
case PAYOUT -> {
var id = String.format(
"%s.%s.%s.%s.%s",
limitsData.getLimit().getConfigId(),
limitsData.getLimit().getRoute().getProviderId(),
limitsData.getLimit().getRoute().getTerminalId(),
limitsData.getLimit().getWalletId(),
limitsData.getLimit().getChange().getCurrency());
gauge(payoutLimitsBoundaryAggregatesMap, Metric.CALENDAR_PAYOUT_LIMITS_BOUNDARY, id,
getPayoutLimitTags(limitsData, limitConfigEntity),
limitsData.getLimit().getBoundary());
gauge(payoutLimitsAmountAggregatesMap, Metric.CALENDAR_PAYOUT_LIMITS_AMOUNT, id,
getPayoutLimitTags(limitsData,
limitConfigEntity), limitsData.getLimit().getAmount());
}
default -> throw new UnknownLimitTypeException(String.format("Limit type '%s' is unknown!", limitType));
}
} }
var registeredMetricsSize = meterRegistryService.getRegisteredMetricsSize(Metric.CALENDAR_LIMITS_BOUNDARY.getName()) + meterRegistryService.getRegisteredMetricsSize(Metric.CALENDAR_LIMITS_AMOUNT.getName()); var registeredMetricsSize =
meterRegistryService.getRegisteredMetricsSize(Metric.CALENDAR_PAYMENT_LIMITS_BOUNDARY.getName()) +
meterRegistryService.getRegisteredMetricsSize(Metric.CALENDAR_PAYMENT_LIMITS_AMOUNT.getName()) +
meterRegistryService.getRegisteredMetricsSize(Metric.CALENDAR_PAYOUT_LIMITS_BOUNDARY.getName()) +
meterRegistryService.getRegisteredMetricsSize(Metric.CALENDAR_PAYOUT_LIMITS_AMOUNT.getName());
log.info("Limits metrics have been registered to 'prometheus', " + log.info("Limits metrics have been registered to 'prometheus', " +
"registeredMetricsSize = {}, clientSize = {}", registeredMetricsSize, limitsDataByInterval.size()); "registeredMetricsSize = {}, clientSize = {}", registeredMetricsSize, limitsDataByInterval.size());
} }
@ -82,7 +117,19 @@ public class LimitsService {
storage.put(id, Double.parseDouble(value)); storage.put(id, Double.parseDouble(value));
} }
private Tags getTags(LimitsData dto, LimitConfigEntity limitConfigEntity) { private LimitType getLimitType(LimitsData limitsData) {
if (!ObjectUtils.isEmpty(limitsData.getPayment())) {
return LimitType.PAYMENT;
}
if (!ObjectUtils.isEmpty(limitsData.getLimit().getWalletId())) {
return LimitType.PAYOUT;
}
throw new UnknownLimitTypeException("Unable to define limit type from this data: " + limitsData);
}
private Tags getPaymentLimitTags(LimitsData dto, LimitConfigEntity limitConfigEntity) {
var tags = Tags.of( var tags = Tags.of(
CustomTag.terminalId(dto.getLimit().getRoute().getTerminalId()), CustomTag.terminalId(dto.getLimit().getRoute().getTerminalId()),
CustomTag.providerId(dto.getLimit().getRoute().getProviderId()), CustomTag.providerId(dto.getLimit().getRoute().getProviderId()),
@ -92,6 +139,24 @@ public class LimitsService {
CustomTag.timeRangType(limitConfigEntity.getTimeRangType().name()), CustomTag.timeRangType(limitConfigEntity.getTimeRangType().name()),
CustomTag.limitContextType(limitConfigEntity.getLimitContextType()), CustomTag.limitContextType(limitConfigEntity.getLimitContextType()),
CustomTag.limitScopeTypes(getLimitScopeTypes(limitConfigEntity.getLimitScopeTypesJson()))); CustomTag.limitScopeTypes(getLimitScopeTypes(limitConfigEntity.getLimitScopeTypesJson())));
return tags.and(getCommonTags(limitConfigEntity));
}
private Tags getPayoutLimitTags(LimitsData dto, LimitConfigEntity limitConfigEntity) {
var tags = Tags.of(
CustomTag.terminalId(dto.getLimit().getRoute().getTerminalId()),
CustomTag.providerId(dto.getLimit().getRoute().getProviderId()),
CustomTag.currency(dto.getLimit().getChange().getCurrency()),
CustomTag.walletId(dto.getLimit().getWalletId()),
CustomTag.configId(dto.getLimit().getConfigId()),
CustomTag.timeRangType(limitConfigEntity.getTimeRangType().name()),
CustomTag.limitContextType(limitConfigEntity.getLimitContextType()),
CustomTag.limitScopeTypes(getLimitScopeTypes(limitConfigEntity.getLimitScopeTypesJson())));
return tags.and(getCommonTags(limitConfigEntity));
}
private Tags getCommonTags(LimitConfigEntity limitConfigEntity) {
Tags tags = Tags.empty();
if (limitConfigEntity.getTimeRangeTypeCalendar() != null) { if (limitConfigEntity.getTimeRangeTypeCalendar() != null) {
tags = tags.and(CustomTag.timeRangeTypeCalendar(limitConfigEntity.getTimeRangeTypeCalendar())); tags = tags.and(CustomTag.timeRangeTypeCalendar(limitConfigEntity.getTimeRangeTypeCalendar()));
} }

View File

@ -9,7 +9,9 @@ import org.opensearch.client.json.JsonData;
import org.opensearch.client.opensearch.OpenSearchClient; import org.opensearch.client.opensearch.OpenSearchClient;
import org.opensearch.client.opensearch._types.SortOrder; import org.opensearch.client.opensearch._types.SortOrder;
import org.opensearch.client.opensearch._types.mapping.FieldType; import org.opensearch.client.opensearch._types.mapping.FieldType;
import org.opensearch.client.opensearch._types.query_dsl.BoolQuery;
import org.opensearch.client.opensearch._types.query_dsl.MatchPhraseQuery; import org.opensearch.client.opensearch._types.query_dsl.MatchPhraseQuery;
import org.opensearch.client.opensearch._types.query_dsl.Query;
import org.opensearch.client.opensearch._types.query_dsl.RangeQuery; import org.opensearch.client.opensearch._types.query_dsl.RangeQuery;
import org.opensearch.client.opensearch.core.search.Hit; import org.opensearch.client.opensearch.core.search.Hit;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -28,6 +30,7 @@ public class OpenSearchService {
private static final String DATE_TIME = "date_time"; private static final String DATE_TIME = "date_time";
private static final String STRICT_DATE_OPTIONAL_TIME = "strict_date_optional_time"; private static final String STRICT_DATE_OPTIONAL_TIME = "strict_date_optional_time";
private static final String HELLGATE = "hellgate"; private static final String HELLGATE = "hellgate";
private static final String FISTFUL = "fistful";
private static final String LIMITS = "\"Limit change commited\""; private static final String LIMITS = "\"Limit change commited\"";
private final OpenSearchProperties openSearchProperties; private final OpenSearchProperties openSearchProperties;
@ -62,9 +65,16 @@ public class OpenSearchService {
.format(STRICT_DATE_OPTIONAL_TIME) .format(STRICT_DATE_OPTIONAL_TIME)
.build() .build()
._toQuery(), ._toQuery(),
new MatchPhraseQuery.Builder() new BoolQuery.Builder()
.field(KUBERNETES_CONTAINER_NAME) .should(new Query(new MatchPhraseQuery.Builder()
.query(HELLGATE) .field(KUBERNETES_CONTAINER_NAME)
.query(HELLGATE)
.build()),
new Query(new MatchPhraseQuery.Builder()
.field(KUBERNETES_CONTAINER_NAME)
.query(FISTFUL)
.build()))
.minimumShouldMatch("1")
.build() .build()
._toQuery()))), ._toQuery()))),
LimitsData.class) LimitsData.class)