Skip to content

Commit d9983aa

Browse files
committed
Add api to fetch api usage data
1 parent afccd2b commit d9983aa

File tree

9 files changed

+79
-13
lines changed

9 files changed

+79
-13
lines changed

server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/serverlog/ServerLog.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@
1515
@Builder
1616
public class ServerLog {
1717
private String userId;
18+
private String orgId;
1819
private String urlPath;
1920
private String httpMethod;
2021
private String requestBody;
2122
private Map<String, String> queryParameters;
2223
private long createTime;
2324

2425
@JsonCreator
25-
private ServerLog(String userId, String urlPath, String httpMethod, String requestBody, Map<String, String> queryParameters, long createTime) {
26+
private ServerLog(String userId, String orgId, String urlPath, String httpMethod, String requestBody, Map<String, String> queryParameters, long createTime) {
2627
this.userId = userId;
28+
this.orgId = orgId;
2729
this.urlPath = urlPath;
2830
this.createTime = createTime;
2931
this.httpMethod = httpMethod;
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package org.lowcoder.infra.serverlog;
22

33
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
4+
import reactor.core.publisher.Mono;
45

56
public interface ServerLogRepository extends ReactiveMongoRepository<ServerLog, String> {
67

8+
Mono<Long> countByOrgId(String orgId);
9+
10+
Mono<Long> countByOrgIdAndCreateTimeBetween(String orgId, Long startMonthEpoch, Long endMonthEpoch);
11+
712
}
813

server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/serverlog/ServerLogService.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import static org.lowcoder.infra.perf.PerfEvent.SERVER_LOG_BATCH_INSERT;
44

5+
import java.time.LocalDateTime;
6+
import java.time.ZoneOffset;
7+
import java.time.temporal.TemporalAdjusters;
58
import java.util.Queue;
69
import java.util.concurrent.ConcurrentLinkedQueue;
710
import java.util.concurrent.TimeUnit;
@@ -13,6 +16,7 @@
1316
import org.springframework.stereotype.Service;
1417

1518
import io.micrometer.core.instrument.Tags;
19+
import reactor.core.publisher.Mono;
1620

1721
@Service
1822
public class ServerLogService {
@@ -42,4 +46,14 @@ private void scheduledInsert() {
4246
perfHelper.count(SERVER_LOG_BATCH_INSERT, Tags.of("size", String.valueOf(result.size())));
4347
});
4448
}
49+
50+
public Mono<Long> getApiUsageCount(String orgId, Boolean lastMonthOnly) {
51+
if(lastMonthOnly != null && lastMonthOnly) {
52+
Long startMonthEpoch = LocalDateTime.now().minusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).toEpochSecond(ZoneOffset.UTC)*1000;
53+
Long endMonthEpoch = LocalDateTime.now().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).toEpochSecond(ZoneOffset.UTC)*1000;
54+
return serverLogRepository.countByOrgIdAndCreateTimeBetween(orgId, startMonthEpoch, endMonthEpoch);
55+
}
56+
return serverLogRepository.countByOrgId(orgId);
57+
}
58+
4559
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/filter/GlobalContextFilter.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,7 @@ public class GlobalContextFilter implements WebFilter, Ordered {
7171
public Mono<Void> filter(@Nonnull ServerWebExchange exchange, @Nonnull WebFilterChain chain) {
7272

7373
return sessionUserService.getVisitorId()
74-
.doOnNext(visitorId -> {
75-
if (isAnonymousUser(visitorId)) {
76-
return;
77-
}
78-
ServerLog serverLog = ServerLog.builder()
79-
.userId(visitorId)
80-
.urlPath(exchange.getRequest().getPath().toString())
81-
.httpMethod(Optional.ofNullable(exchange.getRequest().getMethod()).map(HttpMethod::name).orElse(""))
82-
.createTime(System.currentTimeMillis())
83-
.build();
84-
serverLogService.record(serverLog);
85-
})
74+
.flatMap(visitorId -> saveServerLog(exchange, visitorId))
8675
.flatMap(visitorId -> chain.filter(exchange)
8776
.contextWrite(ctx -> {
8877
Map<String, Object> contextMap = buildContextMap(exchange, visitorId);
@@ -95,6 +84,27 @@ public Mono<Void> filter(@Nonnull ServerWebExchange exchange, @Nonnull WebFilter
9584
}));
9685
}
9786

87+
private Mono<String> saveServerLog(ServerWebExchange exchange, String visitorId) {
88+
if (isAnonymousUser(visitorId)) {
89+
return Mono.just(visitorId);
90+
}
91+
92+
return orgMemberService
93+
.getCurrentOrgMember(visitorId)
94+
.map(orgMember -> {
95+
ServerLog serverLog = ServerLog.builder()
96+
.orgId(orgMember.getOrgId())
97+
.userId(visitorId)
98+
.urlPath(exchange.getRequest().getPath().toString())
99+
.httpMethod(Optional.ofNullable(exchange.getRequest().getMethod()).map(HttpMethod::name).orElse(""))
100+
.createTime(System.currentTimeMillis())
101+
.build();
102+
serverLogService.record(serverLog);
103+
return visitorId;
104+
});
105+
106+
}
107+
98108
private Map<String, Object> buildContextMap(ServerWebExchange serverWebExchange, String visitorId) {
99109
ServerHttpRequest request = serverWebExchange.getRequest();
100110
Map<String, Object> contextMap = request.getHeaders().toSingleValueMap().entrySet()

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import reactor.core.publisher.Mono;
1515

16+
1617
public interface OrgApiService {
1718

1819
Mono<Boolean> leaveOrganization(String orgId);
@@ -45,5 +46,7 @@ public interface OrgApiService {
4546
Mono<Boolean> tryAddUserToOrgAndSwitchOrg(String orgId, String userId);
4647

4748
Mono<ConfigView> getOrganizationConfigs(String orgId);
49+
50+
Mono<Long> getApiUsageCount(String orgId, Boolean lastMonthOnly);
4851
}
4952

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrgApiServiceImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.lowcoder.domain.user.model.Connection;
3939
import org.lowcoder.domain.user.model.User;
4040
import org.lowcoder.domain.user.service.UserService;
41+
import org.lowcoder.infra.serverlog.ServerLogService;
4142
import org.lowcoder.sdk.auth.AbstractAuthConfig;
4243
import org.lowcoder.sdk.config.CommonConfig;
4344
import org.lowcoder.sdk.config.CommonConfig.Workspace;
@@ -76,6 +77,9 @@ public class OrgApiServiceImpl implements OrgApiService {
7677
@Autowired
7778
private AuthenticationService authenticationService;
7879

80+
@Autowired
81+
private ServerLogService serverLogService;
82+
7983
@Override
8084
public Mono<OrgMemberListView> getOrganizationMembers(String orgId, int page, int count) {
8185
return sessionUserService.getVisitorId()
@@ -373,6 +377,12 @@ public Mono<ConfigView> getOrganizationConfigs(String orgId) {
373377
});
374378
}
375379

380+
@Override
381+
public Mono<Long> getApiUsageCount(String orgId, Boolean lastMonthOnly) {
382+
return checkVisitorAdminRole(orgId)
383+
.flatMap(orgMember -> serverLogService.getApiUsageCount(orgId, lastMonthOnly));
384+
}
385+
376386
private Mono<Void> checkIfSaasMode() {
377387
return Mono.defer(() -> {
378388
if (commonConfig.getWorkspace().getMode() == WorkspaceMode.ENTERPRISE) {

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,10 @@ public Mono<ResponseView<Boolean>> updateOrgCommonSettings(@PathVariable String
126126
.map(ResponseView::success);
127127
}
128128

129+
@Override
130+
public Mono<ResponseView<Long>> getOrgApiUsageCount(String orgId, Boolean lastMonthOnly) {
131+
return orgApiService.getApiUsageCount(orgId, lastMonthOnly)
132+
.map(ResponseView::success);
133+
}
134+
129135
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/OrganizationEndpoints.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,15 @@ public Mono<ResponseView<Boolean>> removeUserFromOrg(@PathVariable String orgId,
160160
@PutMapping("/{orgId}/common-settings")
161161
public Mono<ResponseView<Boolean>> updateOrgCommonSettings(@PathVariable String orgId, @RequestBody UpdateOrgCommonSettingsRequest request);
162162

163+
@Operation(
164+
tags = TAG_ORGANIZATION_MANAGEMENT,
165+
operationId = "getOrgApiUsageCount",
166+
summary = "Get the api usage count for the org",
167+
description = "Calculate the used api calls for this organization and return the count"
168+
)
169+
@GetMapping("/{orgId}/api-usage")
170+
public Mono<ResponseView<Long>> getOrgApiUsageCount(@PathVariable String orgId, @RequestParam(required = false) Boolean lastMonthOnly);
171+
163172
public record UpdateOrgCommonSettingsRequest(String key, Object value) {
164173

165174
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/runner/migrations/DatabaseChangelog.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,13 @@ public void completeAuthType(CompleteAuthType completeAuthType) {
175175
completeAuthType.complete();
176176
}
177177

178+
@ChangeSet(order = "019", id = "add-org-id-index-on-server-log", author = "")
179+
public void addOrgIdIndexOnServerLog(MongockTemplate mongoTemplate) {
180+
ensureIndexes(mongoTemplate, ServerLog.class,
181+
makeIndex("orgId")
182+
);
183+
}
184+
178185
public static Index makeIndex(String... fields) {
179186
if (fields.length == 1) {
180187
return new Index(fields[0], Sort.Direction.ASC).named(fields[0]);

0 commit comments

Comments
 (0)