Implement health and logs commands#16
Conversation
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
Health command implementation src/commands/health.ts |
Imports Docker/Kubernetes clients and UI utilities. Adds healthColor(status) to map status strings to colored output. Implements showHealth(target) with validation, async fetching, table formatting, and error handling. Updates registerHealthCommand to wire the new showHealth function. |
Health command tests src/__tests__/health.test.ts |
Mocks containers, pods, logger, spinner, and table renderer. Tests that health all renders a table with container and pod rows. Tests that invalid targets trigger logger.error with "Unknown target". |
Logs command implementation src/commands/logs.ts |
Imports Docker/Kubernetes clients and spinner utility. Adds printStream(value) helper to write Buffer and non-buffer log output to stdout. Implements showLogs(name) with Docker-first lookup by container ID prefix or name, Kubernetes pod fallback, spinner management, and error logging. Updates registerLogsCommand to invoke showLogs. |
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
🐰 Two commands now run swift and bright,
Health checks the pods and containers in sight,
Logs flow from Docker, then Kubernetes stack,
With spinners and tables to guide your track,
A CLI complete, now ship it back! 🚀
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title 'Implement health and logs commands' directly and clearly summarizes the main changes—implementing two command features (health and logs) that were previously placeholder implementations. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
Warning
There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
🔧 ESLint
If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Pull request overview
Implements the previously stubbed health and logs commands. health <target> now queries Docker containers and/or Kubernetes pods (validated against all|containers|pods) and renders a colored status table; logs <name> looks up a container by id-prefix or name and falls back to a pod log lookup. Tests for health are updated to mock the new dependencies.
Changes:
healthcommand fetches running containers/pods via existing helpers and renders viarenderTable, with a status color helper and target validation.logscommand tries Docker first (by id-prefix or name match), falls back to Kubernetes pod logs, and writes the stream tostdout.health.test.tsupdated to mock docker/kubernetes/spinner/table and assert table rendering and unknown-target rejection.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/commands/health.ts | Implements showHealth with target validation, table rendering and color-coded status. |
| src/commands/logs.ts | Implements showLogs with Docker-first lookup and Kubernetes fallback; calls readNamespacedPodLog with positional args. |
| src/tests/health.test.ts | Adds mocks and new tests for table rendering and invalid-target handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return; | ||
| } | ||
|
|
||
| const response = await api.readNamespacedPodLog(pod.metadata.name, pod.metadata.namespace, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 100); |
| export const showLogs = async (name: string) => { | ||
| logger.info?.(`Showing logs for ${name}...`); | ||
| const spinner = createSpinner(`Fetching logs for ${name}...`).start(); | ||
|
|
||
| try { | ||
| const docker = getDockerClient(); | ||
| const containers = await docker.listContainers({ all: true }); | ||
| const match = containers.find((container) => | ||
| container.Id.startsWith(name) || | ||
| container.Names.some((containerName) => containerName.replace(/^\//, '') === name) | ||
| ); | ||
|
|
||
| if (match) { | ||
| const output = await docker.getContainer(match.Id).logs({ stdout: true, stderr: true, tail: 100 }); | ||
| spinner.stop(); | ||
| printStream(output); | ||
| return; | ||
| } | ||
| } catch { | ||
| // Fall through to Kubernetes logs when Docker is unavailable or has no match. | ||
| } | ||
|
|
||
| try { | ||
| const api = getK8sApi(); | ||
| const pods = await api.listPodForAllNamespaces(); | ||
| const pod = pods.body.items.find((item) => item.metadata?.name === name); | ||
|
|
||
| if (!pod?.metadata?.name || !pod.metadata.namespace) { | ||
| spinner.stop(); | ||
| logger.error?.(`No container or pod named ${name} found.`); | ||
| return; | ||
| } | ||
|
|
||
| const response = await api.readNamespacedPodLog(pod.metadata.name, pod.metadata.namespace, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 100); | ||
| spinner.stop(); | ||
| printStream(response.body); | ||
| } catch (error) { | ||
| spinner.stop(); | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| logger.error?.(`Failed to fetch logs for ${name}: ${message}`); | ||
| } | ||
| }; |
| try { | ||
| const docker = getDockerClient(); | ||
| const containers = await docker.listContainers({ all: true }); | ||
| const match = containers.find((container) => | ||
| container.Id.startsWith(name) || | ||
| container.Names.some((containerName) => containerName.replace(/^\//, '') === name) | ||
| ); | ||
|
|
||
| if (match) { | ||
| const output = await docker.getContainer(match.Id).logs({ stdout: true, stderr: true, tail: 100 }); | ||
| spinner.stop(); | ||
| printStream(output); | ||
| return; | ||
| } | ||
| } catch { | ||
| // Fall through to Kubernetes logs when Docker is unavailable or has no match. |
| logger.info?.(`Showing health for ${target}...`); | ||
|
|
||
| if (target !== 'all' && target !== 'containers' && target !== 'pods') { | ||
| logger.error?.(`Unknown target: ${target}. Valid targets are: all, pods, containers.`); |
|
@mzl2233 tag fixed issue in the pr description |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/__tests__/health.test.ts (1)
31-65: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winAdd test coverage for empty results and error handling.
The test suite is missing coverage for two important code paths in
showHealth:
- The empty results warning (line 56-59 in health.ts)
- The catch block error handling (line 65-69 in health.ts)
🧪 Add missing test cases
it('should warn when no workloads are found', async () => { vi.mocked(getRunningContainers).mockResolvedValue([]); vi.mocked(getRunningPods).mockResolvedValue([]); await program.parseAsync(['node', 'test', 'health', 'all']); expect(logger.warn).toHaveBeenCalledWith('No workloads found.'); expect(tableUtils.renderTable).not.toHaveBeenCalled(); }); it('should handle errors when fetching health data', async () => { vi.mocked(getRunningContainers).mockRejectedValue(new Error('Docker connection failed')); await program.parseAsync(['node', 'test', 'health', 'containers']); expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to check containers health')); });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/__tests__/health.test.ts` around lines 31 - 65, Tests are missing coverage for the empty-results and error branches in showHealth: add two unit tests that mock getRunningContainers and getRunningPods to return empty arrays and assert logger.warn('No workloads found.') and that tableUtils.renderTable is not called, and add a test that mocks getRunningContainers to reject (e.g., new Error('Docker connection failed')) then invoke the health command (via program.parseAsync with 'all' or 'containers') and assert logger.error is called with a message containing 'Failed to check containers health' (or the existing error-handling text) so the catch block and empty-warning paths in showHealth are exercised.
🧹 Nitpick comments (3)
src/commands/logs.ts (1)
7-14: ⚡ Quick winSimplify the
printStreamhelper.The Buffer check is unnecessary since
Buffer.toString()andString()both handle the conversion. The function can be reduced to a single line.♻️ Simplified implementation
-const printStream = (value: unknown) => { - if (Buffer.isBuffer(value)) { - process.stdout.write(value.toString()); - return; - } - - process.stdout.write(String(value)); -}; +const printStream = (value: unknown) => process.stdout.write(String(value));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/commands/logs.ts` around lines 7 - 14, The printStream helper has an unnecessary Buffer.isBuffer branch; simplify the function by removing the special-case and always call process.stdout.write(String(value)) in printStream so Buffer and non-Buffer values are handled uniformly (update the function named printStream to a single-line implementation that writes String(value) to process.stdout).src/__tests__/health.test.ts (1)
46-47: ⚡ Quick winAvoid
as anytype assertions in tests.Using
as anybypasses TypeScript's type safety. Use proper mock typing withvi.mocked()helper instead.♻️ Type-safe mocking
- (getRunningContainers as any).mockResolvedValue([{ name: 'web', state: 'running', status: 'Up' }]); - (getRunningPods as any).mockResolvedValue([{ name: 'api', namespace: 'default', status: 'Running', restarts: 0 }]); + vi.mocked(getRunningContainers).mockResolvedValue([{ name: 'web', state: 'running', status: 'Up' }]); + vi.mocked(getRunningPods).mockResolvedValue([{ name: 'api', namespace: 'default', status: 'Running', restarts: 0 }]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/__tests__/health.test.ts` around lines 46 - 47, The tests use unsafe "as any" casts for mocks; replace those with TypeScript-safe mocked helpers by using vi.mocked(getRunningContainers) and vi.mocked(getRunningPods) and call .mockResolvedValue(...) on those typed mocks so you retain type safety; update the two lines that currently reference getRunningContainers and getRunningPods to use vi.mocked(...) instead of the "as any" assertion.src/commands/health.ts (1)
24-27: ⚡ Quick winSimplify target validation.
Using an array with
.includes()is more maintainable and easier to extend when adding new valid targets.♻️ Array-based validation
+ const validTargets = ['all', 'containers', 'pods']; - if (target !== 'all' && target !== 'containers' && target !== 'pods') { + if (!validTargets.includes(target)) { logger.error?.(`Unknown target: ${target}. Valid targets are: all, pods, containers.`); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/commands/health.ts` around lines 24 - 27, Replace the long chained condition checking the "target" variable with an array-based check: define const validTargets = ['all', 'containers', 'pods'] and use if (!validTargets.includes(target)) { logger.error?.(`Unknown target: ${target}. Valid targets are: ${validTargets.join(', ')}.`); return; } so the code uses validTargets.includes(target) and keeps the same logger.error behavior for unknown targets.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/commands/logs.ts`:
- Around line 34-36: The empty catch in src/commands/logs.ts swallows Docker
client errors; change the catch to capture the error (e.g., catch (err)) and
emit a minimal warning before falling back to Kubernetes, e.g., use the existing
logger (processLogger.warn or logger.warn) or console.warn to log "Docker logs
unavailable, falling back to Kubernetes:" plus the error message/stack; keep the
fallback behavior intact so only a brief diagnostic is added.
- Line 49: Replace the fragile positional-argument call to readNamespacedPodLog
with the options-object form: instead of passing many undefineds to reach
tailLines, call readNamespacedPodLog using pod.metadata.name and
pod.metadata.namespace and pass an options object containing tailLines: 100
(e.g., readNamespacedPodLog(pod.metadata.name, pod.metadata.namespace, {
tailLines: 100 })) so the call is clearer and resilient to future signature
changes.
---
Outside diff comments:
In `@src/__tests__/health.test.ts`:
- Around line 31-65: Tests are missing coverage for the empty-results and error
branches in showHealth: add two unit tests that mock getRunningContainers and
getRunningPods to return empty arrays and assert logger.warn('No workloads
found.') and that tableUtils.renderTable is not called, and add a test that
mocks getRunningContainers to reject (e.g., new Error('Docker connection
failed')) then invoke the health command (via program.parseAsync with 'all' or
'containers') and assert logger.error is called with a message containing
'Failed to check containers health' (or the existing error-handling text) so the
catch block and empty-warning paths in showHealth are exercised.
---
Nitpick comments:
In `@src/__tests__/health.test.ts`:
- Around line 46-47: The tests use unsafe "as any" casts for mocks; replace
those with TypeScript-safe mocked helpers by using
vi.mocked(getRunningContainers) and vi.mocked(getRunningPods) and call
.mockResolvedValue(...) on those typed mocks so you retain type safety; update
the two lines that currently reference getRunningContainers and getRunningPods
to use vi.mocked(...) instead of the "as any" assertion.
In `@src/commands/health.ts`:
- Around line 24-27: Replace the long chained condition checking the "target"
variable with an array-based check: define const validTargets = ['all',
'containers', 'pods'] and use if (!validTargets.includes(target)) {
logger.error?.(`Unknown target: ${target}. Valid targets are:
${validTargets.join(', ')}.`); return; } so the code uses
validTargets.includes(target) and keeps the same logger.error behavior for
unknown targets.
In `@src/commands/logs.ts`:
- Around line 7-14: The printStream helper has an unnecessary Buffer.isBuffer
branch; simplify the function by removing the special-case and always call
process.stdout.write(String(value)) in printStream so Buffer and non-Buffer
values are handled uniformly (update the function named printStream to a
single-line implementation that writes String(value) to process.stdout).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 7c613539-474b-4e31-8ae1-4d5a67639d67
📒 Files selected for processing (3)
src/__tests__/health.test.tssrc/commands/health.tssrc/commands/logs.ts
| } catch { | ||
| // Fall through to Kubernetes logs when Docker is unavailable or has no match. | ||
| } |
There was a problem hiding this comment.
Silent catch swallows Docker errors without logging.
The empty catch block means Docker client initialization errors, network issues, or permission problems are silently ignored. Users won't know why Docker logs failed before falling back to Kubernetes.
🔍 Add minimal logging for Docker fallback
- } catch {
- // Fall through to Kubernetes logs when Docker is unavailable or has no match.
+ } catch (error) {
+ logger.debug?.(`Docker unavailable, trying Kubernetes: ${error instanceof Error ? error.message : String(error)}`);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch { | |
| // Fall through to Kubernetes logs when Docker is unavailable or has no match. | |
| } | |
| } catch (error) { | |
| logger.debug?.(`Docker unavailable, trying Kubernetes: ${error instanceof Error ? error.message : String(error)}`); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/commands/logs.ts` around lines 34 - 36, The empty catch in
src/commands/logs.ts swallows Docker client errors; change the catch to capture
the error (e.g., catch (err)) and emit a minimal warning before falling back to
Kubernetes, e.g., use the existing logger (processLogger.warn or logger.warn) or
console.warn to log "Docker logs unavailable, falling back to Kubernetes:" plus
the error message/stack; keep the fallback behavior intact so only a brief
diagnostic is added.
| return; | ||
| } | ||
|
|
||
| const response = await api.readNamespacedPodLog(pod.metadata.name, pod.metadata.namespace, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 100); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the readNamespacedPodLog method signature in the Kubernetes client
rg -A 10 'readNamespacedPodLog' --type=ts -g '!node_modules' -g '!dist'Repository: KDM-cli/kdm-cli
Length of output: 782
🏁 Script executed:
# Find the import statement for the api object
head -50 src/commands/logs.ts | grep -E "import.*api|from.*api"Repository: KDM-cli/kdm-cli
Length of output: 41
🏁 Script executed:
# Check the full context of the logs.ts file to understand the api object
head -80 src/commands/logs.tsRepository: KDM-cli/kdm-cli
Length of output: 2175
🏁 Script executed:
# Search for readNamespacedPodLog in the entire codebase including node_modules types
fd readNamespacedPodLog --type f 2>/dev/null || rg 'readNamespacedPodLog' -g '*.d.ts' -A 5Repository: KDM-cli/kdm-cli
Length of output: 41
🏁 Script executed:
# Find the getK8sApi implementation
cat -n src/kubernetes/client.tsRepository: KDM-cli/kdm-cli
Length of output: 1315
🏁 Script executed:
# Check if there's a package.json to see which Kubernetes client library is used
cat package.json | grep -A 5 -B 5 "@kubernetes"Repository: KDM-cli/kdm-cli
Length of output: 308
🌐 Web query:
@kubernetes/client-node readNamespacedPodLog method signature parameters options object
💡 Result:
In @kubernetes/client-node (TypeScript/JavaScript), CoreV1Api.readNamespacedPodLog is generated and can be called in either a positional-arguments form or (more reliably) an options-object form. 1) Options-object form (recommended) Signature shape (from usage): readNamespacedPodLog({ name, namespace, container,...otherQueryParams }) [1] Example that works: await k8sApi.readNamespacedPodLog({ name: 'nginx', namespace: 'default', container: 'nginx' }) [1] 2) Positional-arguments form (what the generated client expects) People call it with multiple positional parameters (name, namespace, container, follow,...), e.g. the reported call looks like: readNamespacedPodLog('ben', 'default', 'node-red', true, false, undefined, "true", false, undefined, 50, true) [2] Because the repository’s auto-generated docs have been noted as occasionally out-of-date/broken, the most dependable way to get the exact parameter order in your installed version is to inspect the generated code or your IDE IntelliSense (the maintainers explicitly recommend this when docs don’t match) [1]. 3) “options” object parameter You’ll also see a trailing “options” object in other API methods; for readNamespacedPodLog specifically, the GitHub issue on follow=true explains that the generated client’s typing/docs around streaming/follow behavior may not match the underlying REST semantics, and points to custom log handling instead of relying on the generated method for streaming/tailing [2]. 4) Important behavioral note: follow=true doesn’t work as expected with the generated method When follow=true is used, readNamespacedPodLog can “hang” (never resolve its promise), because follow causes the server-side HTTP connection to stay open and the OpenAPI-generated client expects the call to terminate [2]. The follow=true behavior is therefore client-library-specific and may require custom handling (the maintainer points to a custom log implementation in the repo) [2]. If you tell me your exact @kubernetes/client-node version (and whether you want CoreV1Api vs another API), I can extract the exact readNamespacedPodLog TypeScript signature (parameter names and order) for that version from the generated coreV1Api.ts source in that release.
Citations:
- 1: readNamespacedPodLog with follow=true kubernetes-client/javascript#110
- 2: readNamespacedPodLog just hangs if follow set to true kubernetes-client/javascript#689
🌐 Web query:
@kubernetes/client-node CoreV1Api readNamespacedPodLog API documentation
💡 Result:
@kubernetes/client-node CoreV1Api readNamespacedPodLog (JavaScript/TypeScript) documentation summary (as of today, 2026-05-14): 1) What it does / endpoint - The CoreV1Api method ReadNamespacedPodLog maps to the Kubernetes REST endpoint: GET /api/v1/namespaces/{namespace}/pods/{name}/log [1]. 2) How to call it in @kubernetes/client-node - You create the API client via makeApiClient(CoreV1Api) and then call readNamespacedPodLog [2]. - Example (from the @kubernetes/client-node python example for the analogous CoreV1Api method): v1.read_namespaced_pod_log(name=pod_name, namespace=namespace, container=container_name, tail_lines=5) [3]. - Example (JavaScript client usage; minimal parameters): k8sApi.readNamespacedPodLog(name, namespace) and the response body contains the logs [3]. 3) Parameters you typically care about (and why docs may be confusing) - The method signature includes required pod name and namespace (and an optional container), plus common log query options like follow, previous, sinceSeconds, tailLines, limitBytes, etc. The exact signature is auto-generated and should be treated as the source of truth for your installed client version. - There have been issues where the auto-generated docs/signatures were incorrect or misleading for readNamespacedPodLog (for example, required arguments not matching, or docs being out of date). In one report, the fix was to consult the generated code / correct signature, because the published docs were out of date [4]. 4) follow=true behavior (important edge case) - With follow enabled, log streaming behavior may cause the client promise to not resolve as expected (because the HTTP connection is kept open). This is discussed in the kubernetes-client/javascript issue tracker; follow=true “never closes the TCP stream” / the generated client only understands RESTful semantics that assume termination [5]. 5) Getting the most authoritative, up-to-date “documentation” for your installed version - @kubernetes/client-node maintainers point out that “the Kubernetes API Reference is the source-of-truth” for the generated clients and that TypeDoc-generated docs exist and can be built locally [2]. Practical guidance: - Prefer building/inspecting the TypeDoc or generated source for your exact installed @kubernetes/client-node version if you need the exact readNamespacedPodLog parameter order/types (since there have been historical doc/sig mismatches) [2][4]. - If you use follow=true, don’t await completion expecting a finite result; instead treat it as a stream and handle it accordingly [5].
Citations:
- 1: https://github.com/kubernetes-client/go/blob/master/kubernetes/docs/CoreV1Api.md
- 2: https://www.npmjs.com/package/@kubernetes/client-node
- 3: https://github.com/kubernetes-client/python/blob/master/examples/pod_logs.py
- 4: After upgrading to 1.0.0 readNamespacedPodLog broke kubernetes-client/javascript#2196
- 5: readNamespacedPodLog just hangs if follow set to true kubernetes-client/javascript#689
🏁 Script executed:
# Check if there are type definitions or examples in node_modules
find node_modules/@kubernetes -name "*.d.ts" -type f 2>/dev/null | head -5Repository: KDM-cli/kdm-cli
Length of output: 41
🏁 Script executed:
# Look for examples or tests that show how readNamespacedPodLog is used
rg 'readNamespacedPodLog' -A 2 -B 2 --type=ts --type=jsRepository: KDM-cli/kdm-cli
Length of output: 412
Use the options object pattern for readNamespacedPodLog instead of positional arguments.
Passing 10 undefined values to reach the tailLines parameter is fragile and unmaintainable. The @kubernetes/client-node library supports an options-object form that is both clearer and more resistant to future breaking changes:
- const response = await api.readNamespacedPodLog(pod.metadata.name, pod.metadata.namespace, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 100);
+ const response = await api.readNamespacedPodLog({
+ name: pod.metadata.name,
+ namespace: pod.metadata.namespace,
+ tailLines: 100
+ });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/commands/logs.ts` at line 49, Replace the fragile positional-argument
call to readNamespacedPodLog with the options-object form: instead of passing
many undefineds to reach tailLines, call readNamespacedPodLog using
pod.metadata.name and pod.metadata.namespace and pass an options object
containing tailLines: 100 (e.g., readNamespacedPodLog(pod.metadata.name,
pod.metadata.namespace, { tailLines: 100 })) so the call is clearer and
resilient to future signature changes.
utkarsh232005
left a comment
There was a problem hiding this comment.
Resolve the merge conflicts
This implements the health command so it reports Docker containers and Kubernetes pods instead of only printing a placeholder. It also wires the logs command to fetch Docker container logs first and fall back to Kubernetes pod logs when needed. The focused command tests pass and the project builds successfully.
Summary by CodeRabbit