CLICLItypeA command you run, rather than a dependency you import.See every one →What this type is →independently maintainedindependently maintainedoriginPublished by one person or a small company outside SAP. Says nothing about quality; the readings say that.See every one →

@saptools/cf-logs

A command line and typed Node.js library that fetches and streams the logs of one Cloud Foundry app and parses them into structured rows.

Reading a Cloud Foundry app's logs from shell scripts, VS Code extensions, Node services or test runners means parsing the raw text cf logs prints. This package wraps cf logs --recent and cf logs <app> for one app at a time and turns plain-text, JSON and multiline output into rows with a level, the router's method, status, latency and tenant, and two separate request identifiers; a compact mode shortens rows and keeps a reference to the full row saved under ~/.saptools. The vcapRequestId on a row is the field its README uses to find the matching trace with @saptools/cf-otel. It reads only what the official cf CLI returns, so a snapshot reaches back as far as Cloud Foundry's --recent window, and it redacts nothing it prints or saves.

Facts

Latestv0.8.1ReleasedLast pushLicenceMIT

Where it sits

Lives in
Provides
LoggingBTPLoggingcapabilitySeeing what a running service did, in a form something can read afterwards — levels, a formatter that suits a laptop and one that suits a log service.
Runs
Cloud Foundry
Requires
Node.jsNode.jsoutside the atlasThe command line and its API run on Node.js 20 or later, beside the official cf CLI on the path.

Who is behind it

Đông TrầnĐông TrầnPersonMaintains this
In the atlas: maintains 18, contributes to 18
@dongitran
maintainer

What it declares

Every artifact

Type
CLI
Origin
Independently maintained
Runs on
Cloud Foundry

As a CLI

Distributed through
npm

Connections3

Install

npm add @saptools/cf-logs

Derived from the package name. No recipe recorded; the README has the configuration.

Where @saptools/cf-logs runsBy its type: a CLI is run from a terminalcallsdocumentedrequiresYour terminal, actorYour terminalNode.js, systemNode.jssystem@saptools/cf-logs, module@saptools/cf-logs
SAPnot SAP's, or the project's ownstated in the documentdocumented only

README

quoted from dongitran/saptools under MIT, read
dongitran/saptools/packages/cf-logs/README.mdOn GitHub

📜 @saptools/cf-logs

Turn SAP BTP Cloud Foundry logs into a reusable engine, not a one-off UI feature.

Fetch snapshots, stream live output, normalize plain-text and JSON rows, emit compact high-signal context, and persist bounded log state to disk through one CLI and one typed Node.js API.

npm version license node install size types

Install • Quick Start • CLI • Store • Security


✨ Features

  • 📥 Recent snapshots — run cf logs --recent, normalize the result, and optionally persist it
  • 📡 Live streams — wrap cf logs <app> with batching, reconnection, bounded in-memory state, and typed events
  • 🧠 Log normalization — handle plain text, JSON logs, multiline continuations, and router access metadata such as method, request, status, latency, tenant, client IP, and separate correlation & hop request IDs
  • 🪶 Compact output — project logs into concise rows with optional refs back to full saved rows
  • 🗃️ Bounded local store — write snapshots to ~/.saptools/cf-logs-store.json with atomic file updates and locking
  • 🧩 CLI and typed API — use the package from shell scripts, VSCode extensions, Node services, or test runners
  • 🧪 Fake-backed E2E coverage — snapshot and stream flows are verified without live SAP access

📦 Install

# Global CLI
npm install -g @saptools/cf-logs

# Or as a dependency
npm install @saptools/cf-logs
# pnpm add @saptools/cf-logs
# yarn add @saptools/cf-logs

Note

Requires Node.js >= 20 and the official cf CLI on PATH.


Updates

Every command first checks npm for a newer @saptools/cf-logs (at most once an hour, one small request with a 2-second timeout) and, when one exists, installs that exact version with the package manager that owns the running binary and re-runs the command you typed on the new version. Both steps are announced on stderr; nothing is printed when the install is already current:

cf-logs: updating 0.7.0 -> 0.8.0 ...
cf-logs: updated to 0.8.0; re-running the command

If the install cannot complete, one stderr line gives the manual command and the command runs on the installed version; that version is not retried for a day. cf-logs self-update forces the check and install now; cf-logs self-update --check only reports.

ControlEffect
SAPTOOLS_AUTO_UPDATE=on|notify|offon (default) installs and re-runs; notify prints the manual command once per version; off never checks. Applies to every @saptools CLI.
CF_LOGS_AUTO_UPDATEsame values, this CLI only; wins over the global variable
SAPTOOLS_UPDATE_INTERVAL_MINUTESminutes between checks (default 60; 0 checks on every run)
SAPTOOLS_NPM_REGISTRYregistry to check and install from (default: npm's configured registry, then npmjs)
SAPTOOLS_UPDATE_DEBUG=1explain on stderr why nothing happened

The updater switches itself off in CI (CI set), under NODE_ENV=test or NO_UPDATE_NOTIFIER, when the binary runs from a source checkout, an npm link or an npx cache, and inside the re-run itself. It never writes to stdout, never asks for input, never uses sudo, and never moves onto a prerelease. Its state lives in ~/.saptools/updates/.

🚀 Quick Start

# 1. Export credentials used for cf api/auth
export SAP_EMAIL="operator@example.test"
export SAP_PASSWORD="credential-placeholder"

# 2. Fetch a structured snapshot
cf-logs snapshot \
  --region ap10 \
  --org sample-org \
  --space sample \
  --app demo-app \
  --json

# 3. Start a live stream as line-delimited JSON events
cf-logs stream \
  --region ap10 \
  --org sample-org \
  --space sample \
  --app demo-app \
  --json

# 4. Stream compact rows and keep refs for drill-down
cf-logs stream \
  --region ap10 \
  --org sample-org \
  --space sample \
  --app demo-app \
  --compact \
  --save

If you already know the CF API endpoint, replace --region ap10 with --api-endpoint https://api.cf.ap10.hana.ondemand.com.


🧰 CLI

Shared targeting flags

Most commands use the same target shape:

FlagDescription
--region <key>CF region key such as ap10
--api-endpoint <url>Explicit CF API endpoint instead of a region key
--org <name>CF org name
--space <name>CF space name
--app <name>CF app name
--email <value>Override SAP_EMAIL
--password <value>Override SAP_PASSWORD

--region or --api-endpoint is required. Credentials default to SAP_EMAIL and SAP_PASSWORD.

Warning

Prefer the environment variables over --password <value>. Process arguments are visible to other users on the machine via tools like ps, so passing credentials inline can leak them. The --password flag is kept as an explicit override for one-off scripts only.

cf-logs snapshot

Fetch recent logs for one app. By default the command prints bounded raw text. Use --json for structured rows, --compact for condensed output, and --save to persist. Cloud Foundry controls the --recent window; --since, --search, and --min-level filter rows after those logs are returned.

cf-logs snapshot \
  --region ap10 \
  --org sample-org \
  --space sample \
  --app demo-app \
  --json \
  --save
FlagDescription
--jsonEmit a full JSON snapshot object
--compactEmit compact rows instead of raw text or a full snapshot
--compact-message-limit <count>Maximum characters per compact message/body (default: 500)
--compact-ttl-minutes <count>Minutes before compact drill-down refs expire (default: 60)
--savePersist to the local store; with --compact, create temporary full-row refs instead
--since <duration>Filter rows after CF returns recent logs; accepts 15m, 45m, 1h, or 1d
--search <text>Keep rows matching text case-insensitively
--min-level <level>Keep rows at or above trace, debug, info, warn, error, or fatal
--log-limit <count>Maximum parsed rows and bounded raw-text budget
cf-logs stream

Start a live log stream for one app. In JSON mode the command emits line-delimited events:

  • {"type":"state",...}
  • {"type":"lines",...}
cf-logs stream \
  --region ap10 \
  --org sample-org \
  --space sample \
  --app demo-app \
  --json

Useful stream options:

FlagDescription
--jsonEmit line-delimited JSON events
--compactEmit compact parsed rows instead of raw CF lines
--compact-message-limit <count>Maximum characters per compact message/body (default: 500)
--compact-ttl-minutes <count>Minutes before compact drill-down refs expire (default: 60)
--savePersist to the local store; with --compact, create temporary full-row refs instead
--max-lines <count>Stop after emitting N streamed lines
--search <text>Keep rows matching text case-insensitively
--min-level <level>Keep rows at or above trace, debug, info, warn, error, or fatal
--log-limit <count>Maximum parsed rows and bounded raw-text budget
--flush-interval-ms <ms>Batch window before append events are emitted
--retry-initial-ms <ms>Initial reconnect delay after unexpected stream exits
--retry-max-ms <ms>Maximum reconnect delay
cf-logs show

Retrieve a full saved compact row by ref. Refs are emitted only when --compact --save is used.

cf-logs show 7f3a9c2b:42
cf-logs show 7f3a9c2b:42 --json
cf-logs session

Inspect or clear temporary compact drill-down sessions. Sessions expire after 60 minutes by default.

cf-logs session list
cf-logs session list --json
cf-logs session prune
cf-logs session clear
cf-logs apps

List started apps with running instances for one org/space.

cf-logs apps --region ap10 --org sample-org --space sample --json
cf-logs store path

Print the package-managed log store path.

cf-logs store path
cf-logs store list

Inspect cached store entries.

cf-logs store list
cf-logs store list --json
cf-logs store clear

Remove every cached entry from the package-managed log store. The store file remains in place but is rewritten with an empty entries list.

cf-logs store clear
cf-logs --version

Print the installed @saptools/cf-logs semantic version.

cf-logs --version

🔗 Request Identifiers

A parsed row exposes three identifier fields. They are not interchangeable, and picking the wrong one is the difference between finding a request and finding a few hundred.

FieldSourceGrain
correlationIdx_correlationid on a router line; correlation_id, x_correlation_id or x_correlationid in a JSON payloadOne business transaction — constant across every hop
vcapRequestIdvcap_request_id on a router line; x_vcap_request_id or request_id in a JSON payloadOne HTTP hop — a fresh value per request
requestIdrouter lines only — whichever of the two that line carried, correlation firstLegacy single slot, unchanged since 0.7.0

requestId predates the split and is kept byte-for-byte so existing callers keep working. It cannot tell you which identifier it holds, which is why the two typed fields exist.

One wrinkle worth knowing: on a JSON application row requestId is always empty — it has only ever been populated from router lines. The compact projection still fills its own requestId slot from the payload, exactly as it did in 0.7.0. correlationId and vcapRequestId are populated on both row kinds, which is the point of having them.

Joining a log row to an OpenTelemetry trace

vcapRequestId is the field to join on. Measured against a live tenant over 1,504 server spans, it resolved to exactly one trace every time; within that same sample correlationId averaged 13.29 traces per value and reached 777, and over a full retention window a single value has been measured covering 6,796 traces — because it identifies the whole transaction rather than one request.

The matching span attribute is span.attributes.http@request@header@x-vcap-request-id:

# 1. read the hop id off the log row (compact keeps it, so no full snapshot needed)
cf-logs snapshot --app demo-app --compact --json | jq -r '.rows[] | select(.vcapRequestId) | .vcapRequestId'

# 2. resolve it to a trace, then analyze that trace
cf-otel find --vcap-request-id <id>
cf-otel selftime <traceId>

Note

Spans reach the trace index a few seconds after the log line, so a lookup run immediately can report no rows for a trace that exists. Needs @saptools/cf-otel 0.7.0 or newer. On older versions the flag does not exist and = does not match this field, because the attribute is stored as a JSON array rendered to text (["<id>"]) — use --service <app> --attr 'http@request@header@x-vcap-request-id~<id>' there.

In compact output vcapRequestId is printed whenever the row has one, even when it repeats requestId. Suppressing the duplicate saved a few characters but made two rows carrying different kinds of identifier print identically, which defeats the point of joining on it. requestId itself is byte-for-byte what 0.7.0 emitted.


📁 Store File

The package-managed store lives here:

~/.saptools/cf-logs-store.json

It contains bounded full-fidelity entries keyed by:

  • apiEndpoint
  • org
  • space
  • app

Each entry stores:

  • rawText
  • fetchedAt
  • updatedAt
  • rowCount
  • truncated

The store is an implementation detail. Prefer readStore(), persistSnapshot(), cf-logs store path, or cf-logs store list over parsing the file directly.


🔐 Data Notes

  • The CLI and runtime do not redact log content.
  • Persisted snapshots are bounded and written with file locking plus atomic replace semantics.
  • Store and session files can contain credentials, tokens, personal data, or business data if the application logs them.
  • The store file and compact session files are not safe for public repositories.
  • Compact mode reduces token volume only; it is not a privacy feature.
  • Temporary compact sessions live under ~/.saptools/cf-logs-sessions/ and are pruned after their TTL.

❓ FAQ

Does this package depend on VSCode?

No. The package is intentionally UI-agnostic. It exposes a CLI, a runtime engine, normalization helpers, and store helpers that can be used by VSCode, terminal tools, tests, or backend processes.

Why separate this from an extension?

Because log normalization, streaming, compact projection, and store management are reusable engine concerns. Keeping them in a package makes the IDE layer smaller, easier to test, and easier to evolve.

Does snapshot or stream save data automatically?

No. Persistence is opt-in. Use --save in the CLI or enable persistSnapshots / persistStreamAppends in CfLogsRuntime.

Can I use an explicit API endpoint instead of a region key?

Yes. Pass --api-endpoint <url> in the CLI or apiEndpoint in the Node.js API.


🛠️ Development

From the monorepo root:

pnpm install
pnpm --filter @saptools/cf-logs cspell
pnpm --filter @saptools/cf-logs lint
pnpm --filter @saptools/cf-logs typecheck
pnpm --filter @saptools/cf-logs test:unit
pnpm --filter @saptools/cf-logs test:e2e
pnpm --filter @saptools/cf-logs build
pnpm --filter @saptools/cf-logs check

🤝 Author

Maintained by dongtran.

MIT, read

History

Latest

v0.8.1

  1. v0.8.0

  2. v0.7.0

  3. v0.6.2

  4. v0.6.1

  5. v0.6.0

  6. v0.5.1

  7. v0.5.0

  8. v0.4.0

  9. v0.3.0

  10. v0.2.2

  11. v0.2.1

  12. v0.2.0

  13. v0.1.3

  14. v0.1.2

  15. v0.1.1

  16. v0.1.0

On npm
3downloads per week, npm
Weekly downloads for @saptools/cf-logs26 complete calendar weeks from 2026-04-27 to 2026-10-25; the latest total is 3.27 Apr – 3 May: 04 May – 10 May: 44111 May – 17 May: 5418 May – 24 May: 22025 May – 31 May: 1221 Jun – 7 Jun: 908 Jun – 14 Jun: 15015 Jun – 21 Jun: 10622 Jun – 28 Jun: 1,25429 Jun – 5 Jul: 9106 Jul – 12 Jul: 28813 Jul – 19 Jul: 26620 Jul – 26 Jul: 43127 Jul – 2 Aug: 2493 Aug – 9 Aug: 26310 Aug – 16 Aug: 37917 Aug – 23 Aug: 24224 Aug – 30 Aug: 2031 Aug – 6 Sept: 5127 Sept – 13 Sept: 5514 Sept – 20 Sept: 2921 Sept – 27 Sept: 2028 Sept – 4 Oct: 285 Oct – 11 Oct: 1912 Oct – 18 Oct: 419 Oct – 25 Oct: 3
Logging
  1. SAP Application Logging service for SAP BTPCollects Cloud Foundry or Kyma logs into a searchable Kibana
  2. SAP Cloud LoggingOpenSearch-based store for logs, metrics and traces
  3. @saptools/cf-tailMerged log tail of every started app in a Cloud Foundry space

Details

Sources4
Added by handdiscovered herechecked
npm registry, @saptools/cf-logsversion, releases, installschecked
github.com/git+https://github.com/dongitran/saptools.gittree, pushes, contributors, CIchecked
packages/cf-logs/README.mdquoted, and what the entry declareschecked

Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.

Compatibility and provenance
deploymentCloud Foundry
latestv0.8.1
first release
releases and cadence17, ~1d median
discovered viaAdded by hand
first seen in the atlas
ecosystem and domainbtp, operations-and-runtime
History in the atlas1
  1. First seen.
For your agent
Ref
artifact:saptools-cf-logs
JSON
/artifacts/saptools-cf-logs.json
MCP
Connecting an agent