Skip to content

Commit bb2b510

Browse files
author
serverpod_cloud
committed
feat: 340dc12056460880ea7b92f76d703d589a135909
1 parent 903f222 commit bb2b510

5 files changed

Lines changed: 66 additions & 40 deletions

File tree

ground_control_client/lib/src/protocol/client.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ class EndpointLogs extends _i1.EndpointRef {
638638
@override
639639
String get name => 'logs';
640640

641-
/// Fetches log records from the specified project.
641+
/// Fetches log records from the specified capsule.
642642
_i2.Stream<_i21.LogRecord> fetchRecords({
643643
String? cloudProjectId,
644644
String? cloudCapsuleId,
@@ -659,7 +659,23 @@ class EndpointLogs extends _i1.EndpointRef {
659659
{},
660660
);
661661

662-
/// Tails log records from the specified project.
662+
/// Fetches the N most recent records from the specified capsule,
663+
/// where N is the specified limit.
664+
/// Records are returned in ascending time order.
665+
///
666+
/// This call will hold until all the records are fetched in order to sort them.
667+
_i2.Stream<_i21.LogRecord> fetchRecentRecords({
668+
required String cloudCapsuleId,
669+
int? limit,
670+
}) => caller
671+
.callStreamingServerEndpoint<_i2.Stream<_i21.LogRecord>, _i21.LogRecord>(
672+
'logs',
673+
'fetchRecentRecords',
674+
{'cloudCapsuleId': cloudCapsuleId, 'limit': limit},
675+
{},
676+
);
677+
678+
/// Tails log records from the specified capsule.
663679
/// Continues until the client unsubscribes, [limit] is reached,
664680
/// or the internal max limit is reached.
665681
_i2.Stream<_i21.LogRecord> tailRecords({

serverpod_cloud_cli/lib/command_runner/commands/log_command.dart

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import 'package:serverpod_cloud_cli/shared/exceptions/cloud_cli_usage_exception.
88

99
import 'categories.dart';
1010

11+
const _defaultLogLimit = 50;
12+
1113
enum LogOption<V> implements OptionDefinition<V> {
1214
projectId(ProjectIdOption()),
1315
limit(
1416
IntOption(
1517
argName: 'limit',
1618
helpText: 'The maximum number of log records to fetch.',
17-
defaultsTo: 100,
19+
defaultsTo: _defaultLogLimit,
1820
min: 0,
1921
),
2022
),
@@ -72,14 +74,25 @@ class CloudLogCommand extends CloudCliCommand<LogOption> {
7274
String get category => CommandCategories.control;
7375

7476
@override
75-
String get usageExamples => '''\n
77+
String get usageExamples =>
78+
'''\n
7679
Examples
7780
78-
View the most recent logs (default: last 10 minutes).
81+
View the most recent logs (default limit is $_defaultLogLimit records).
7982
8083
\$ scloud log
8184
8285
86+
View the most recent logs with UTC timestamps and a custom limit.
87+
88+
\$ scloud log --utc --limit 100
89+
90+
91+
Stream logs in real-time.
92+
93+
\$ scloud log --tail
94+
95+
8396
View logs from the last hour using duration.
8497
8598
\$ scloud log 1h
@@ -110,16 +123,6 @@ Examples
110123
111124
\$ scloud log --since 2025-01-15T14:00:00Z --until 30m
112125
113-
114-
Stream logs in real-time.
115-
116-
\$ scloud log --tail
117-
118-
119-
View logs with UTC timestamps and a custom limit.
120-
121-
\$ scloud log --utc --limit 100
122-
123126
''';
124127

125128
CloudLogCommand({required super.logger}) : super(options: LogOption.values);
@@ -158,8 +161,6 @@ Examples
158161
'The --until value must be after --since value.',
159162
);
160163
}
161-
} else if (until == null && since == null) {
162-
defaultSince = DateTime.now().subtract(Duration(minutes: 30));
163164
}
164165

165166
if (tailOpt == true) {

serverpod_cloud_cli/lib/commands/logs/logs.dart

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,21 @@ abstract class LogsFeature {
2020
'to ${before?.toTzString(inUtc) ?? 'newest'}. Display time zone: $timezoneName.',
2121
);
2222

23-
final recordStream = cloudApiClient.logs.fetchRecords(
24-
cloudProjectId: projectId,
25-
beforeTime: before,
26-
afterTime: after,
27-
limit: limit,
28-
);
23+
final Stream<LogRecord> recordStream;
24+
if (before == null && after == null) {
25+
recordStream = cloudApiClient.logs.fetchRecentRecords(
26+
cloudCapsuleId: projectId,
27+
limit: limit,
28+
);
29+
} else {
30+
recordStream = cloudApiClient.logs.fetchRecords(
31+
cloudCapsuleId: projectId,
32+
beforeTime: before,
33+
afterTime: after,
34+
limit: limit,
35+
);
36+
}
37+
2938
await _outputLogStream(writeln, recordStream, limit: limit, inUtc: inUtc);
3039
}
3140

@@ -42,7 +51,7 @@ abstract class LogsFeature {
4251
writeln('Tailing logs. Display time zone: $timezoneName.');
4352

4453
final recordStream = cloudApiClient.logs.tailRecords(
45-
cloudProjectId: projectId,
54+
cloudCapsuleId: projectId,
4655
limit: limit,
4756
);
4857
await LogsFeature._outputLogStream(
@@ -68,7 +77,7 @@ abstract class LogsFeature {
6877
);
6978

7079
final recordStream = cloudApiClient.logs.fetchBuildLog(
71-
cloudProjectId: projectId,
80+
cloudCapsuleId: projectId,
7281
attemptId: attemptId,
7382
);
7483
await _outputLogStream(writeln, recordStream, inUtc: inUtc);

serverpod_cloud_cli/lib/commands/status/status.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ abstract class StatusCommands {
8888
return switch (status) {
8989
DeployProgressStatus.unknown => '⬛',
9090
DeployProgressStatus.awaiting => '⬛',
91-
DeployProgressStatus.running => '🟩',
91+
DeployProgressStatus.running => '',
9292
DeployProgressStatus.success => '✅',
9393
DeployProgressStatus.failure => '❌',
9494
DeployProgressStatus.cancelled => '❌',

serverpod_cloud_cli/test_integration/commands/log_command/log_command_test.dart

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ void main() {
2626
final mockRecords = [
2727
LogRecord(
2828
cloudProjectId: projectId,
29-
cloudCapsuleId: '1',
29+
cloudCapsuleId: projectId,
3030
recordId: '1',
3131
timestamp: logTimestamp,
3232
content: 'Log message 1',
3333
),
3434
LogRecord(
3535
cloudProjectId: projectId,
36-
cloudCapsuleId: '2',
36+
cloudCapsuleId: projectId,
3737
recordId: '2',
3838
timestamp: logTimestamp,
3939
content: 'Log message 2',
@@ -53,7 +53,7 @@ void main() {
5353
setUp(() async {
5454
when(
5555
() => client.logs.fetchRecords(
56-
cloudProjectId: projectId,
56+
cloudCapsuleId: projectId,
5757
beforeTime: null,
5858
afterTime: any(named: 'afterTime'),
5959
limit: any(named: 'limit'),
@@ -87,7 +87,7 @@ void main() {
8787
line: '2024-01-01 00:00:00.000Z | | Log message 2',
8888
),
8989
equalsLineCall(
90-
line: '-- End of log stream -- 2 records (limit 100) --',
90+
line: '-- End of log stream -- 2 records (limit 50) --',
9191
),
9292
]),
9393
);
@@ -98,7 +98,7 @@ void main() {
9898
setUp(() async {
9999
when(
100100
() => client.logs.fetchRecords(
101-
cloudProjectId: projectId,
101+
cloudCapsuleId: projectId,
102102
beforeTime: any(named: 'beforeTime'),
103103
afterTime: any(named: 'afterTime'),
104104
limit: any(named: 'limit'),
@@ -132,7 +132,7 @@ void main() {
132132
line: '2024-01-01 00:00:00.000Z | | Log message 2',
133133
),
134134
equalsLineCall(
135-
line: '-- End of log stream -- 2 records (limit 100) --',
135+
line: '-- End of log stream -- 2 records (limit 50) --',
136136
),
137137
]),
138138
);
@@ -143,7 +143,7 @@ void main() {
143143
setUp(() async {
144144
when(
145145
() => client.logs.fetchRecords(
146-
cloudProjectId: projectId,
146+
cloudCapsuleId: projectId,
147147
beforeTime: DateTime.parse('2030-12-01T00:00:00Z'),
148148
afterTime: null,
149149
limit: any(named: 'limit'),
@@ -181,7 +181,7 @@ void main() {
181181
line: '2024-01-01 00:00:00.000Z | | Log message 2',
182182
),
183183
equalsLineCall(
184-
line: '-- End of log stream -- 2 records (limit 100) --',
184+
line: '-- End of log stream -- 2 records (limit 50) --',
185185
),
186186
]),
187187
);
@@ -192,7 +192,7 @@ void main() {
192192
setUp(() async {
193193
when(
194194
() => client.logs.fetchRecords(
195-
cloudProjectId: projectId,
195+
cloudCapsuleId: projectId,
196196
beforeTime: null,
197197
afterTime: DateTime.parse('2020-12-01T00:00:00Z'),
198198
limit: any(named: 'limit'),
@@ -230,7 +230,7 @@ void main() {
230230
line: '2024-01-01 00:00:00.000Z | | Log message 2',
231231
),
232232
equalsLineCall(
233-
line: '-- End of log stream -- 2 records (limit 100) --',
233+
line: '-- End of log stream -- 2 records (limit 50) --',
234234
),
235235
]),
236236
);
@@ -241,7 +241,7 @@ void main() {
241241
setUp(() async {
242242
when(
243243
() => client.logs.fetchRecords(
244-
cloudProjectId: projectId,
244+
cloudCapsuleId: projectId,
245245
beforeTime: DateTime.parse('2030-01-01T00:00:00Z'),
246246
afterTime: DateTime.parse('2020-12-01T00:00:00Z'),
247247
limit: any(named: 'limit'),
@@ -281,7 +281,7 @@ void main() {
281281
line: '2024-01-01 00:00:00.000Z | | Log message 2',
282282
),
283283
equalsLineCall(
284-
line: '-- End of log stream -- 2 records (limit 100) --',
284+
line: '-- End of log stream -- 2 records (limit 50) --',
285285
),
286286
]),
287287
);
@@ -292,7 +292,7 @@ void main() {
292292
setUp(() async {
293293
when(
294294
() => client.logs.tailRecords(
295-
cloudProjectId: projectId,
295+
cloudCapsuleId: projectId,
296296
limit: any(named: 'limit'),
297297
),
298298
).thenAnswer((final _) => Stream.fromIterable(mockRecords));
@@ -318,7 +318,7 @@ void main() {
318318
line: '2024-01-01 00:00:00.000Z | | Log message 2',
319319
),
320320
equalsLineCall(
321-
line: '-- End of log stream -- 2 records (limit 100) --',
321+
line: '-- End of log stream -- 2 records (limit 50) --',
322322
),
323323
]),
324324
);

0 commit comments

Comments
 (0)