Skip to content

Commit 9a73a2f

Browse files
Display dates in Quota and Usage messages according to the timezone configurations (#8230)
Co-authored-by: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com>
1 parent 240db19 commit 9a73a2f

File tree

23 files changed

+196
-163
lines changed

23 files changed

+196
-163
lines changed

engine/schema/src/main/java/com/cloud/usage/UsageVO.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.cloud.usage;
1818

1919
import java.util.Date;
20+
import java.util.TimeZone;
2021

2122
import javax.persistence.Column;
2223
import javax.persistence.Entity;
@@ -27,9 +28,11 @@
2728
import javax.persistence.Temporal;
2829
import javax.persistence.TemporalType;
2930

31+
import com.cloud.utils.DateUtil;
3032
import org.apache.cloudstack.api.InternalIdentity;
3133
import org.apache.cloudstack.usage.Usage;
3234
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
35+
import org.apache.commons.lang3.StringUtils;
3336

3437
@Entity
3538
@Table(name = "cloud_usage")
@@ -400,6 +403,12 @@ public void setHidden(boolean hidden) {
400403

401404
@Override
402405
public String toString() {
403-
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType", "startDate", "endDate");
406+
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "usageId", "usageType");
407+
}
408+
409+
public String toString(TimeZone timeZone) {
410+
String startDateString = DateUtil.displayDateInTimezone(timeZone, getStartDate());
411+
String endDateString = DateUtil.displayDateInTimezone(timeZone, getEndDate());
412+
return String.format("%s,\"startDate\":\"%s\",\"endDate\":\"%s\"}", StringUtils.chop(this.toString()), startDateString, endDateString);
404413
}
405414
}

framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaAlertManagerImpl.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import javax.inject.Inject;
3030
import javax.naming.ConfigurationException;
3131

32+
import com.cloud.utils.DateUtil;
3233
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
3334
import org.apache.cloudstack.quota.constant.QuotaConfig;
3435
import org.apache.cloudstack.quota.constant.QuotaConfig.QuotaEmailTemplateTypes;
@@ -156,9 +157,9 @@ public void checkAndSendQuotaAlertEmails() {
156157
if (account == null) {
157158
continue; // the account is removed
158159
}
159-
if (logger.isDebugEnabled()) {
160-
logger.debug("checkAndSendQuotaAlertEmails: Check id=" + account.getId() + " bal=" + accountBalance + ", alertDate=" + alertDate + ", lockable=" + lockable);
161-
}
160+
logger.debug("checkAndSendQuotaAlertEmails: Check id={} bal={}, alertDate={}, lockable={}", account.getId(),
161+
accountBalance, DateUtil.displayDateInTimezone(QuotaManagerImpl.getUsageAggregationTimeZone(), alertDate),
162+
lockable);
162163
if (accountBalance.compareTo(zeroBalance) < 0) {
163164
if (_lockAccountEnforcement && (lockable == 1)) {
164165
if (_quotaManager.isLockable(account)) {

framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java

+32-37
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
5050
import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter;
5151
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
52-
import org.apache.cloudstack.utils.usage.UsageUtils;
5352
import org.apache.commons.collections.CollectionUtils;
5453
import org.apache.commons.lang3.BooleanUtils;
54+
import org.apache.commons.lang3.ObjectUtils;
5555
import org.apache.commons.lang3.StringUtils;
5656
import org.apache.commons.lang3.math.NumberUtils;
5757
import org.springframework.stereotype.Component;
@@ -85,8 +85,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
8585
@Inject
8686
protected PresetVariableHelper presetVariableHelper;
8787

88-
private TimeZone _usageTimezone;
89-
private int _aggregationDuration = 0;
88+
private static TimeZone usageAggregationTimeZone = TimeZone.getTimeZone("GMT");
9089
static final BigDecimal GiB_DECIMAL = BigDecimal.valueOf(ByteScaleUtils.GiB);
9190
List<Account.Type> lockablesAccountTypes = Arrays.asList(Account.Type.NORMAL, Account.Type.DOMAIN_ADMIN);
9291

@@ -112,24 +111,16 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
112111
mergeConfigs(configs, params);
113112
}
114113

115-
String aggregationRange = configs.get("usage.stats.job.aggregation.range");
116-
String timeZoneStr = configs.get("usage.aggregation.timezone");
117-
118-
if (timeZoneStr == null) {
119-
timeZoneStr = "GMT";
120-
}
121-
_usageTimezone = TimeZone.getTimeZone(timeZoneStr);
122-
123-
_aggregationDuration = Integer.parseInt(aggregationRange);
124-
if (_aggregationDuration < UsageUtils.USAGE_AGGREGATION_RANGE_MIN) {
125-
logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + UsageUtils.USAGE_AGGREGATION_RANGE_MIN);
126-
_aggregationDuration = UsageUtils.USAGE_AGGREGATION_RANGE_MIN;
127-
}
128-
logger.info("Usage timezone = " + _usageTimezone + " AggregationDuration=" + _aggregationDuration);
114+
String usageAggregationTimeZoneStr = ObjectUtils.defaultIfNull(configs.get("usage.aggregation.timezone"), "GMT");
115+
usageAggregationTimeZone = TimeZone.getTimeZone(usageAggregationTimeZoneStr);
129116

130117
return true;
131118
}
132119

120+
public static TimeZone getUsageAggregationTimeZone() {
121+
return usageAggregationTimeZone;
122+
}
123+
133124
@Override
134125
public boolean start() {
135126
if (logger.isInfoEnabled()) {
@@ -158,8 +149,9 @@ protected void processQuotaBalanceForAccount(AccountVO accountVo, List<QuotaUsag
158149
Date startDate = firstQuotaUsage.getStartDate();
159150
Date endDate = firstQuotaUsage.getStartDate();
160151

161-
logger.info(String.format("Processing quota balance for account [%s] between [%s] and [%s].", accountToString, startDate,
162-
accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate()));
152+
logger.info("Processing quota balance for account [{}] between [{}] and [{}].", accountToString,
153+
DateUtil.displayDateInTimezone(usageAggregationTimeZone, startDate),
154+
DateUtil.displayDateInTimezone(usageAggregationTimeZone, accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate()));
163155

164156
BigDecimal aggregatedUsage = BigDecimal.ZERO;
165157
long accountId = accountVo.getAccountId();
@@ -246,17 +238,20 @@ protected void saveQuotaAccount(long accountId, BigDecimal aggregatedUsage, Date
246238

247239
protected BigDecimal aggregateCreditBetweenDates(Long accountId, Long domainId, Date startDate, Date endDate, String accountToString) {
248240
List<QuotaBalanceVO> creditsReceived = _quotaBalanceDao.findCreditBalance(accountId, domainId, startDate, endDate);
249-
logger.debug(String.format("Account [%s] has [%s] credit entries before [%s].", accountToString, creditsReceived.size(), endDate));
241+
logger.debug("Account [{}] has [{}] credit entries before [{}].", accountToString, creditsReceived.size(),
242+
DateUtil.displayDateInTimezone(usageAggregationTimeZone, endDate));
250243

251244
BigDecimal aggregatedUsage = BigDecimal.ZERO;
252245

253-
logger.debug(String.format("Aggregating the account [%s] credit entries before [%s].", accountToString, endDate));
246+
logger.debug("Aggregating the account [{}] credit entries before [{}].", accountToString,
247+
DateUtil.displayDateInTimezone(usageAggregationTimeZone, endDate));
254248

255249
for (QuotaBalanceVO credit : creditsReceived) {
256250
aggregatedUsage = aggregatedUsage.add(credit.getCreditBalance());
257251
}
258252

259-
logger.debug(String.format("The aggregation of the account [%s] credit entries before [%s] resulted in the value [%s].", accountToString, endDate, aggregatedUsage));
253+
logger.debug("The aggregation of the account [{}] credit entries before [{}] resulted in the value [{}].",
254+
accountToString, DateUtil.displayDateInTimezone(usageAggregationTimeZone, endDate), aggregatedUsage);
260255

261256
return aggregatedUsage;
262257
}
@@ -306,15 +301,15 @@ protected List<UsageVO> getPendingUsageRecordsForQuotaAggregation(AccountVO acco
306301
protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO account, List<UsageVO> usageRecords,
307302
Map<Integer, Pair<List<QuotaTariffVO>, Boolean>> mapQuotaTariffsPerUsageType) {
308303
String accountToString = account.reflectionToString();
309-
logger.info(String.format("Calculating quota usage of [%s] usage records for account [%s].", usageRecords.size(), accountToString));
304+
logger.info("Calculating quota usage of [{}] usage records for account [{}].", usageRecords.size(), accountToString);
310305

311306
List<Pair<UsageVO, QuotaUsageVO>> pairsUsageAndQuotaUsage = new ArrayList<>();
312307

313308
try (JsInterpreter jsInterpreter = new JsInterpreter(QuotaConfig.QuotaActivationRuleTimeout.value())) {
314309
for (UsageVO usageRecord : usageRecords) {
315310
int usageType = usageRecord.getUsageType();
316311

317-
if (Boolean.FALSE.equals(shouldCalculateUsageRecord(account,usageRecord))) {
312+
if (!shouldCalculateUsageRecord(account, usageRecord)) {
318313
pairsUsageAndQuotaUsage.add(new Pair<>(usageRecord, null));
319314
continue;
320315
}
@@ -339,8 +334,8 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO
339334

340335
protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageRecord) {
341336
if (Boolean.FALSE.equals(QuotaConfig.QuotaAccountEnabled.valueIn(accountVO.getAccountId()))) {
342-
logger.debug(String.format("Considering usage record [%s] as calculated and skipping it because account [%s] has the quota plugin disabled.",
343-
usageRecord, accountVO.reflectionToString()));
337+
logger.debug("Considering usage record [{}] as calculated and skipping it because account [{}] has the quota plugin disabled.",
338+
usageRecord.toString(usageAggregationTimeZone), accountVO.reflectionToString());
344339
return false;
345340
}
346341
return true;
@@ -366,9 +361,8 @@ protected List<QuotaUsageVO> persistUsagesAndQuotaUsagesAndRetrievePersistedQuot
366361

367362
protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<QuotaTariffVO> quotaTariffs, boolean hasAnyQuotaTariffWithActivationRule,
368363
JsInterpreter jsInterpreter, String accountToString) {
369-
String usageRecordToString = usageRecord.toString();
370-
logger.debug(String.format("Validating usage record [%s] for account [%s] against [%s] quota tariffs.", usageRecordToString, accountToString,
371-
quotaTariffs.size()));
364+
String usageRecordToString = usageRecord.toString(usageAggregationTimeZone);
365+
logger.debug("Validating usage record [{}] for account [{}] against [{}] quota tariffs.", usageRecordToString, accountToString, quotaTariffs.size());
372366

373367
PresetVariables presetVariables = getPresetVariables(hasAnyQuotaTariffWithActivationRule, usageRecord);
374368
BigDecimal aggregatedQuotaTariffsValue = BigDecimal.ZERO;
@@ -406,7 +400,7 @@ protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActiva
406400
protected BigDecimal getQuotaTariffValueToBeApplied(QuotaTariffVO quotaTariff, JsInterpreter jsInterpreter, PresetVariables presetVariables) {
407401
String activationRule = quotaTariff.getActivationRule();
408402
BigDecimal quotaTariffValue = quotaTariff.getCurrencyValue();
409-
String quotaTariffToString = quotaTariff.toString();
403+
String quotaTariffToString = quotaTariff.toString(usageAggregationTimeZone);
410404

411405
if (StringUtils.isEmpty(activationRule)) {
412406
logger.debug(String.format("Quota tariff [%s] does not have an activation rule, therefore we will use the quota tariff value [%s] in the calculation.",
@@ -468,10 +462,11 @@ protected boolean isQuotaTariffInPeriodToBeApplied(UsageVO usageRecord, QuotaTar
468462
Date quotaTariffEndDate = quotaTariff.getEndDate();
469463

470464
if ((quotaTariffEndDate != null && usageRecordStartDate.after(quotaTariffEndDate)) || usageRecordEndDate.before(quotaTariffStartDate)) {
471-
logger.debug(String.format("Not applying quota tariff [%s] in usage record [%s] of account [%s] due to it is out of the period to be applied. Period of the usage"
472-
+ " record [startDate: %s, endDate: %s], period of the quota tariff [startDate: %s, endDate: %s].", quotaTariff, usageRecord.toString(), accountToString,
473-
DateUtil.getOutputString(usageRecordStartDate), DateUtil.getOutputString(usageRecordEndDate), DateUtil.getOutputString(quotaTariffStartDate),
474-
DateUtil.getOutputString(quotaTariffEndDate)));
465+
logger.debug("Not applying quota tariff [{}] in usage record [{}] of account [{}] due to it is out of the period to be applied. Period of the usage"
466+
+ " record [startDate: {}, endDate: {}], period of the quota tariff [startDate: {}, endDate: {}].", quotaTariff.toString(usageAggregationTimeZone),
467+
usageRecord.toString(usageAggregationTimeZone), accountToString, DateUtil.displayDateInTimezone(usageAggregationTimeZone, usageRecordStartDate),
468+
DateUtil.displayDateInTimezone(usageAggregationTimeZone, usageRecordEndDate), DateUtil.displayDateInTimezone(usageAggregationTimeZone, quotaTariffStartDate),
469+
DateUtil.displayDateInTimezone(usageAggregationTimeZone, quotaTariffEndDate));
475470

476471
return false;
477472
}
@@ -497,11 +492,11 @@ protected Map<Integer, Pair<List<QuotaTariffVO>, Boolean>> createMapQuotaTariffs
497492
}
498493

499494
protected QuotaUsageVO createQuotaUsageAccordingToUsageUnit(UsageVO usageRecord, BigDecimal aggregatedQuotaTariffsValue, String accountToString) {
500-
String usageRecordToString = usageRecord.toString();
495+
String usageRecordToString = usageRecord.toString(usageAggregationTimeZone);
501496

502497
if (aggregatedQuotaTariffsValue.equals(BigDecimal.ZERO)) {
503-
logger.debug(String.format("Usage record [%s] for account [%s] does not have quota tariffs to be calculated, therefore we will mark it as calculated.",
504-
usageRecordToString, accountToString));
498+
logger.debug("No tariffs were applied to usage record [{}] of account [{}] or they resulted in 0; We will only mark the usage record as calculated.",
499+
usageRecordToString, accountToString);
505500
return null;
506501
}
507502

framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
//under the License.
1717
package org.apache.cloudstack.quota.vo;
1818

19+
import com.cloud.utils.DateUtil;
1920
import org.apache.cloudstack.api.InternalIdentity;
2021
import org.apache.cloudstack.quota.constant.QuotaTypes;
2122
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
2223

2324
import com.cloud.utils.db.GenericDao;
25+
import org.apache.commons.lang3.StringUtils;
2426

2527
import javax.persistence.Column;
2628
import javax.persistence.Entity;
@@ -33,6 +35,7 @@
3335

3436
import java.math.BigDecimal;
3537
import java.util.Date;
38+
import java.util.TimeZone;
3639
import java.util.UUID;
3740

3841
@Entity
@@ -261,6 +264,12 @@ public boolean setUsageTypeData(int usageType) {
261264

262265
@Override
263266
public String toString() {
264-
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "uuid", "name", "effectiveOn", "endDate");
265-
};
267+
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "uuid", "name", "usageName");
268+
}
269+
270+
public String toString(TimeZone timeZone) {
271+
String startDateString = DateUtil.displayDateInTimezone(timeZone, getEffectiveOn());
272+
String endDateString = DateUtil.displayDateInTimezone(timeZone, getEndDate());
273+
return String.format("%s,\"startDate\":\"%s\",\"endDate\":\"%s\"}", StringUtils.chop(this.toString()), startDateString, endDateString);
274+
}
266275
}

0 commit comments

Comments
 (0)