Skip to content

Commit f6d74f0

Browse files
committed
improve logging
Signed-off-by: Hoang Pham <[email protected]>
1 parent 20eaf90 commit f6d74f0

File tree

5 files changed

+314
-28
lines changed

5 files changed

+314
-28
lines changed

lib/Controller/WhiteboardController.php

+115-10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use OCP\AppFramework\Http\Attribute\PublicPage;
2525
use OCP\AppFramework\Http\DataResponse;
2626
use OCP\IRequest;
27+
use Psr\Log\LoggerInterface;
2728

2829
/**
2930
* @psalm-suppress UndefinedClass
@@ -39,6 +40,7 @@ public function __construct(
3940
private WhiteboardContentService $contentService,
4041
private ExceptionService $exceptionService,
4142
private ConfigService $configService,
43+
private LoggerInterface $logger,
4244
) {
4345
parent::__construct($appName, $request);
4446
}
@@ -48,15 +50,60 @@ public function __construct(
4850
#[PublicPage]
4951
public function show(int $fileId): DataResponse {
5052
try {
51-
$jwt = $this->getJwtFromRequest();
53+
$this->logger->warning('WhiteboardController::show - Request for fileId: ' . $fileId, [
54+
'file_id' => $fileId,
55+
'request_params' => $this->request->getParams()
56+
]);
5257

53-
$userId = $this->jwtService->getUserIdFromJWT($jwt);
58+
$jwt = $this->getJwtFromRequest();
5459

55-
$user = $this->getUserFromIdServiceFactory->create($userId)->getUser();
60+
$this->logger->warning('JWT token retrieved, attempting to extract user ID');
5661

57-
$file = $this->getFileServiceFactory->create($user, $fileId)->getFile();
62+
$userId = $this->jwtService->getUserIdFromJWT($jwt);
5863

59-
$data = $this->contentService->getContent($file);
64+
$this->logger->warning('User ID extracted from JWT: ' . $userId);
65+
66+
try {
67+
$user = $this->getUserFromIdServiceFactory->create($userId)->getUser();
68+
} catch (Exception $e) {
69+
$this->logger->error('Failed to create user object for: ' . $userId, [
70+
'error' => $e->getMessage()
71+
]);
72+
throw $e;
73+
}
74+
75+
$this->logger->warning('User object created for: ' . $userId);
76+
77+
try {
78+
$file = $this->getFileServiceFactory->create($user, $fileId)->getFile();
79+
} catch (Exception $e) {
80+
$this->logger->error('Failed to retrieve file for fileId: ' . $fileId, [
81+
'error' => $e->getMessage()
82+
]);
83+
throw $e;
84+
}
85+
86+
$this->logger->warning('File retrieved for fileId: ' . $fileId);
87+
88+
try {
89+
$data = $this->contentService->getContent($file);
90+
} catch (Exception $e) {
91+
$this->logger->error('Failed to retrieve content for file', [
92+
'file_id' => $fileId,
93+
'error' => $e->getMessage()
94+
]);
95+
throw $e;
96+
}
97+
98+
$this->logger->warning('Content retrieved for file', [
99+
'file_id' => $fileId,
100+
'data_size' => is_array($data) ? count($data) : 'not array'
101+
]);
102+
103+
$this->logger->warning('Content retrieved for file', [
104+
'file_id' => $fileId,
105+
'data_size' => is_array($data) ? count($data) : 'not array'
106+
]);
60107

61108
return new DataResponse(['data' => $data]);
62109
} catch (Exception $e) {
@@ -69,15 +116,55 @@ public function show(int $fileId): DataResponse {
69116
#[PublicPage]
70117
public function update(int $fileId, array $data): DataResponse {
71118
try {
72-
$this->validateBackendSharedToken($fileId);
119+
$this->logger->warning('WhiteboardController::update - Request for fileId: ' . $fileId, [
120+
'file_id' => $fileId,
121+
'request_params' => json_encode(substr(json_encode($this->request->getParams()), 0, 500)) . '...'
122+
]);
73123

74-
$userId = $this->getUserIdFromRequest();
124+
$this->validateBackendSharedToken($fileId);
75125

76-
$user = $this->getUserFromIdServiceFactory->create($userId)->getUser();
126+
$this->logger->warning('Backend shared token validated for fileId: ' . $fileId);
77127

78-
$file = $this->getFileServiceFactory->create($user, $fileId)->getFile();
128+
$userId = $this->getUserIdFromRequest();
79129

80-
$this->contentService->updateContent($file, $data);
130+
$this->logger->warning('User ID extracted from request: ' . $userId);
131+
132+
try {
133+
$user = $this->getUserFromIdServiceFactory->create($userId)->getUser();
134+
} catch (Exception $e) {
135+
$this->logger->error('Failed to create user object for: ' . $userId, [
136+
'error' => $e->getMessage()
137+
]);
138+
throw $e;
139+
}
140+
141+
$this->logger->warning('User object created for: ' . $userId);
142+
143+
try {
144+
$file = $this->getFileServiceFactory->create($user, $fileId)->getFile();
145+
} catch (Exception $e) {
146+
$this->logger->error('Failed to retrieve file for fileId: ' . $fileId, [
147+
'error' => $e->getMessage()
148+
]);
149+
throw $e;
150+
}
151+
152+
$this->logger->warning('File retrieved for fileId: ' . $fileId);
153+
154+
try {
155+
$this->contentService->updateContent($file, $data);
156+
} catch (Exception $e) {
157+
$this->logger->error('Failed to update content for file', [
158+
'file_id' => $fileId,
159+
'error' => $e->getMessage()
160+
]);
161+
throw $e;
162+
}
163+
164+
$this->logger->warning('Content updated for file', [
165+
'file_id' => $fileId,
166+
'data_size' => count($data)
167+
]);
81168

82169
return new DataResponse(['status' => 'success']);
83170
} catch (Exception $e) {
@@ -88,6 +175,7 @@ public function update(int $fileId, array $data): DataResponse {
88175
private function getJwtFromRequest(): string {
89176
$authHeader = $this->request->getHeader('Authorization');
90177
if (sscanf($authHeader, 'Bearer %s', $jwt) !== 1) {
178+
$this->logger->error('Invalid JWT format in Authorization header');
91179
throw new UnauthorizedException();
92180
}
93181
return (string)$jwt;
@@ -100,21 +188,38 @@ private function getUserIdFromRequest(): string {
100188
private function validateBackendSharedToken(int $fileId): void {
101189
$backendSharedToken = $this->request->getHeader('X-Whiteboard-Auth');
102190
if (!$backendSharedToken || !$this->verifySharedToken($backendSharedToken, $fileId)) {
191+
$this->logger->error('Invalid backend shared token', [
192+
'file_id' => $fileId,
193+
'token_present' => !empty($backendSharedToken),
194+
'token_length' => strlen((string)$backendSharedToken)
195+
]);
196+
103197
throw new InvalidUserException('Invalid backend shared token');
104198
}
199+
200+
$this->logger->warning('Backend shared token validated successfully for fileId: ' . $fileId);
105201
}
106202

107203
private function verifySharedToken(string $token, int $fileId): bool {
108204
[$roomId, $timestamp, $signature] = explode(':', $token);
109205

110206
if ($roomId !== (string)$fileId) {
111207
return false;
208+
} else {
209+
$this->logger->warning('Room ID matches file ID: ' . $fileId);
112210
}
113211

114212
$sharedSecret = $this->configService->getWhiteboardSharedSecret();
213+
214+
$this->logger->warning('Shared secret retrieved, length: ' . strlen($sharedSecret));
215+
115216
$payload = "$roomId:$timestamp";
116217
$expectedSignature = hash_hmac('sha256', $payload, $sharedSecret);
117218

219+
$this->logger->warning('Token validation', [
220+
'token_valid' => hash_equals($expectedSignature, $signature)
221+
]);
222+
118223
return hash_equals($expectedSignature, $signature);
119224
}
120225
}

lib/Service/ExceptionService.php

+45-2
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,78 @@
1616
use OCP\AppFramework\Http\DataResponse;
1717
use OCP\Files\NotFoundException;
1818
use OCP\Files\NotPermittedException;
19+
use Psr\Log\LoggerInterface;
1920

2021
/**
2122
* @psalm-suppress UndefinedClass
2223
*/
2324
final class ExceptionService {
25+
public function __construct(
26+
private LoggerInterface $logger,
27+
) {
28+
}
29+
2430
public function handleException(Exception $e): DataResponse {
2531
$statusCode = $this->getStatusCode($e);
2632
$message = $this->getMessage($e);
2733

34+
// Log the exception with context for debugging
35+
$this->logger->error('Exception handled: ' . get_class($e), [
36+
'message' => $e->getMessage(),
37+
'code' => $e->getCode(),
38+
'file' => $e->getFile(),
39+
'line' => $e->getLine(),
40+
'status_code' => $statusCode,
41+
'user_message' => $message,
42+
'trace' => $this->getTraceAsString($e),
43+
]);
44+
2845
return new DataResponse(['message' => $message], $statusCode);
2946
}
3047

3148
private function getStatusCode(Exception $e): int {
32-
return match (true) {
49+
$statusCode = match (true) {
3350
$e instanceof NotFoundException => Http::STATUS_NOT_FOUND,
3451
$e instanceof NotPermittedException => Http::STATUS_FORBIDDEN,
3552
$e instanceof UnauthorizedException => Http::STATUS_UNAUTHORIZED,
3653
$e instanceof InvalidUserException => Http::STATUS_BAD_REQUEST,
3754
default => (int)($e->getCode() ?: Http::STATUS_INTERNAL_SERVER_ERROR),
3855
};
56+
57+
$this->logger->warning('Determined status code for exception', [
58+
'exception_type' => get_class($e),
59+
'status_code' => $statusCode,
60+
]);
61+
62+
return $statusCode;
3963
}
4064

4165
private function getMessage(Exception $e): string {
42-
return match (true) {
66+
$message = match (true) {
4367
$e instanceof NotFoundException => 'File not found',
4468
$e instanceof NotPermittedException => 'Permission denied',
4569
$e instanceof UnauthorizedException => 'Unauthorized',
4670
$e instanceof InvalidUserException => 'Invalid user',
4771
default => $e->getMessage() ?: 'An error occurred',
4872
};
73+
74+
$this->logger->warning('Generated user-facing message', [
75+
'exception_type' => get_class($e),
76+
'original_message' => $e->getMessage(),
77+
'user_message' => $message,
78+
]);
79+
80+
return $message;
81+
}
82+
83+
private function getTraceAsString(Exception $e): string {
84+
$traceLines = explode("\n", $e->getTraceAsString());
85+
$limitedTrace = array_slice($traceLines, 0, 10);
86+
87+
if (count($traceLines) > 10) {
88+
$limitedTrace[] = '... ' . (count($traceLines) - 10) . ' more lines truncated';
89+
}
90+
91+
return implode("\n", $limitedTrace);
4992
}
5093
}

0 commit comments

Comments
 (0)