# Quick start

> Send your first log line to JustLog3 Cloud in about two minutes, from Python, Go or plain HTTP.

JustLog3 Cloud is a hosted log service. Your program sends plain-text log lines over HTTPS with an API token; you read them in the dashboard, get a Telegram message when a session grows past a threshold, and ask an AI assistant about them. The Free plan takes 5,000 lines a day and needs no card.

## 1. Get an API token

[Sign up](https://jl3-cloud.site/authentication/signup/) with Google or GitHub. The token is in the **API token** panel on your dashboard. Anyone with the token can write to your workspace, so keep it out of public repositories; you can rotate it from the same panel.

## 2. Install a library

Official libraries batch lines, retry on network errors and keep writing a local log file, so a cloud outage never loses data:

```bash
pip install justlog3                      # Python 3.8+
go get github.com/OAzizjon/justlog3/go    # Go 1.23+, standard library only
```

Any other language can use the [HTTP API](https://jl3-cloud.site/docs/http-api/) directly.

## 3. Write your first log

Python:

```python
from justlog3 import Logger, set_api_token

set_api_token('YOUR_API_TOKEN', url='https://jl3-cloud.site/api/logs/')

logger = Logger('app.log')
logger.log('Hello from Python!', green=True)
```

Go:

```go
package main

import (
	"log"

	justlog3 "github.com/OAzizjon/justlog3/go"
)

func main() {
	err := justlog3.SetAPIToken("YOUR_API_TOKEN",
		justlog3.WithURL("https://jl3-cloud.site/api/logs/"))
	if err != nil {
		log.Fatal(err)
	}
	defer justlog3.Shutdown()

	logger, err := justlog3.NewLogger("app.log")
	if err != nil {
		log.Fatal(err)
	}
	logger.Log("Hello from Go!", justlog3.Green())
}
```

curl:

```bash
curl -X POST "https://jl3-cloud.site/api/logs/" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: text/plain" \
  -H "X-JustLog-Logger: manual" \
  --data "Hello from HTTP!"
```

## 4. Check your logs

Lines are sent in batches: every 75 lines, every 5 seconds and when the program exits. Open **Logs** in the dashboard: each run of your program is a session, and long sessions open on their own page.

## Next steps

- [Telegram alerts](https://jl3-cloud.site/docs/alerts/): get a message when a session crosses 100 lines.
- [AI assistant](https://jl3-cloud.site/docs/ai-assistant/): ask why a run failed, with your logs and GitHub repositories in context.
- [Plans and limits](https://jl3-cloud.site/docs/limits/): what each plan includes.


# Python

> Install the justlog3 package, log to a file and to the cloud, levels, batching and shutdown behaviour.

The `justlog3` package writes log lines to a file in batches and, once you set an API token, sends them to JustLog3 Cloud from a background thread. `log()` never waits for the disk or the network.

## Install

```bash
pip install justlog3
```

Python 3.8 or newer. `httpx`, used for cloud sending, is installed with the package. Source and benchmarks: [github.com/OAzizjon/justlog3](https://github.com/OAzizjon/justlog3).

## Log to a file

```python
from justlog3 import Logger

logger = Logger('app.log')

logger.log('Hi...')
logger.log('debug', off_console=True)
logger.log('There is some error!', red=True)
logger.log('OK', green=True)
logger.log('There is critical error!', red=True, custom_prefix='CRITICAL!!')
```

The console shows colored lines; `app.log` gets one line per call with a prefix and a local timestamp with milliseconds:

```text
GREY:2026-10-05 14:03:12.517 - Hi...
RED:2026-10-05 14:03:12.518 - There is some error!
GREEN:2026-10-05 14:03:12.518 - OK
```

## Send to JustLog3 Cloud

```python
import os
from justlog3 import Logger, set_api_token

set_api_token(os.environ['JUSTLOG3_TOKEN'], url='https://jl3-cloud.site/api/logs/')
logger = Logger('app.log')
logger.log('This line goes to the file and to the cloud')
```

Call `set_api_token()` once, before or after creating loggers. Keep the token in an environment variable rather than in code.

- Lines are sent every `flush_interval` seconds (default 5), or sooner once `cloud_cycles` lines (default 75) are waiting.
- A request carries at most 5,000 lines and 512 KB of text; bodies from 1 KB are gzip-compressed.
- Each logger keeps up to 10,000 unsent lines; beyond that the oldest are dropped with a single warning.
- No answer or HTTP 5xx: the batch is resent with the same sequence number, so the server stores it once. The wait starts at 5 s and doubles up to 5 minutes.
- HTTP 429: nothing is sent until `Retry-After`; lines stay buffered.
- HTTP 401 / 403: cloud sending stops, files keep being written. Call `set_api_token()` again with a valid token.
- On exit the remaining lines are sent, waiting at most `timeout` seconds.

`set_api_token(token, *, url=..., flush_interval=5.0, timeout=5.0)` raises `ValueError` for an empty token.

## Levels

```python
from justlog3 import BasicLogger

logger = BasicLogger('app.log', console_level='INFO')
logger.debug('cache warmed')         # file and cloud only: below INFO
logger.info('server started')
logger.warning('disk 85% full')
logger.error('payment failed')
logger.critical('database is down')
```

`console_level` only filters the console. Every line still goes to the file and the cloud.

## Shutdown and signals

- Normal exit: every logger is flushed by an `atexit` hook.
- SIGTERM (`docker stop`, systemd, `kill`): JustLog3 turns the signal into a normal exit so the flush runs. Call `off_signal_handler()` before creating any logger to keep your own handler.
- `kill -9` or a power cut loses what is still in the buffer: at most `cycles - 1` lines (default 49).
- Call `shutdown()` yourself before `os._exit()`.

## Logger options

| Parameter | Default | Meaning |
|---|---|---|
| `filename` | `'app.log'` | `.log` is added if missing |
| `with_time` | `True` | timestamp in every line |
| `filemode` | `'a'` | `'w'` empties the file once, on creation |
| `cycles` | `50` | lines per disk write |
| `cloud_cycles` | `75` | waiting lines that wake the cloud sender |
| `off_sigmask` | `False` | don't hold back SIGTERM during writes (Linux, macOS) |


# Go

> Use the justlog3 Go module: loggers, options, cloud sending and why Shutdown() matters.

The `justlog3` Go module writes log lines to a file from a background goroutine and, once you set an API token, sends them to JustLog3 Cloud. It uses only the standard library.

## Install

```bash
go get github.com/OAzizjon/justlog3/go
```

Go 1.23 or newer. The package name is `justlog3`. Reference: [pkg.go.dev](https://pkg.go.dev/github.com/OAzizjon/justlog3/go).

## Log to a file and the cloud

```go
package main

import (
	"log"
	"os"

	justlog3 "github.com/OAzizjon/justlog3/go"
)

func main() {
	err := justlog3.SetAPIToken(os.Getenv("JUSTLOG3_TOKEN"),
		justlog3.WithURL("https://jl3-cloud.site/api/logs/"))
	if err != nil {
		log.Fatal(err)
	}
	defer justlog3.Shutdown() // flushes files and sends what is left

	logger, err := justlog3.NewLogger("app.log")
	if err != nil {
		log.Fatal(err)
	}
	logger.Log("Hi...")
	logger.Log("There is some error!", justlog3.Red())
	logger.Log("OK", justlog3.Green())
	logger.Log("There is critical error!", justlog3.Red(), justlog3.Prefix("CRITICAL!!"))
}
```

## Always call Shutdown

Go has no exit hook. Without `justlog3.Shutdown()` (or `logger.Flush()` / `logger.Close()`) the last buffered lines are lost. `log.Fatal` and `os.Exit` skip deferred calls, so flush before them.

## Levels

```go
logger, _ := justlog3.NewBasicLogger("app.log", justlog3.WithConsoleLevel("INFO"))
logger.Debug("only in the file and cloud")
logger.Info("started")
logger.Successf("processed %d items", 42)
logger.Error("payment failed")
```

`WithConsoleLevel` only filters the console. Every level has an `f` variant (`Infof`, `Errorf`, ...).

## How cloud sending works

- Each logger keeps a cloud buffer of up to 10,000 lines; the oldest lines are dropped on overflow.
- Batches go out when `WithCloudCycles(n)` lines are waiting (default 75) or every flush interval (default 5 s), at most `WithMaxBatch(n)` lines (default 100) and 512 KB of text each. Bodies from 1 KB are gzip-compressed.
- No answer or HTTP 5xx: the batch is resent unchanged with the same `X-JustLog-Seq`, so the server stores it once.
- HTTP 429: nothing is sent until `Retry-After`. HTTP 413: later batches carry half as many lines.
- HTTP 401 / 403: cloud sending stops and files keep being written. Call `SetAPIToken` again to resume.

Cloud options: `WithURL(url)`, `WithFlushInterval(d)`, `WithTimeout(d)`, `WithMaxBatch(n)`.

## Logger options

| Option | Default | Meaning |
|---|---|---|
| `WithTime(bool)` | `true` | timestamp in every line |
| `WithFilemode("a" or "w")` | `"a"` | `"w"` truncates the file once on creation |
| `WithCycles(n)` | `50` | lines per disk write |
| `WithCloudCycles(n)` | `75` | waiting lines that wake the cloud sender |
| `WithConsoleLevel(level)` | `"DEBUG"` | `BasicLogger` only |

The file stays open and is reopened if it is renamed or deleted, so log rotation works, on Windows too.


# HTTP API

> Send logs from any language with one POST request: headers, compression, responses and retries.

Any language or tool that can make an HTTPS POST request can send logs. The body is plain text; every line of it is one log line. Send a batch of lines per request rather than one request per line. A machine-readable description is at [/openapi.json](https://jl3-cloud.site/openapi.json) (OpenAPI 3.1).

## Endpoint

```text
POST https://jl3-cloud.site/api/logs/
Authorization: Bearer YOUR_API_TOKEN
Content-Type: text/plain
```

## Examples

curl (macOS, Linux):

```bash
curl -X POST "https://jl3-cloud.site/api/logs/" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: text/plain" \
  -H "X-JustLog-Logger: manual" \
  --data "Hello from HTTP!"
```

Windows PowerShell:

```powershell
Invoke-RestMethod -Method Post -Uri "https://jl3-cloud.site/api/logs/" `
  -Headers @{ Authorization = "Bearer YOUR_API_TOKEN"; "X-JustLog-Logger" = "manual" } `
  -ContentType "text/plain" -Body "Hello from HTTP!"
```

A gzip-compressed batch with curl:

```bash
printf 'line one\nline two\n' | gzip | curl -X POST "https://jl3-cloud.site/api/logs/" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: text/plain" \
  -H "Content-Encoding: gzip" \
  --data-binary @-
```

## Request headers

| Header | Meaning |
|---|---|
| `Authorization` | Required. `Bearer YOUR_API_TOKEN` |
| `Content-Type` | Required. `text/plain` |
| `Content-Encoding` | Optional. `gzip`, `deflate` or `zstd` for a compressed body |
| `X-JustLog-Logger` | Source name shown in Logs, e.g. `api` (up to 255 characters, default `unknown`) |
| `X-JustLog-Session` | Groups the requests of one run (up to 255 characters) |
| `X-JustLog-Seq` | A positive number that orders a session. A retry with the same session and Seq within 30 minutes is acknowledged and stored once |
| `X-JustLog-UTC-Offset` | Your UTC offset in seconds east of UTC, e.g. `18000` for UTC+5 |

## Responses

| Status | Meaning |
|---|---|
| `202` | Stored. `X-JustLog-Lines-Accepted` is how many lines were stored, `X-JustLog-Lines-Rejected` how many did not fit into today's limit, `X-JustLog-Lines-Remaining` what is left today. `X-JustLog-Repeat: 1` means this session and Seq were already stored |
| `400` | Not `text/plain`, an empty body, or a corrupt compressed body |
| `401` | Missing, wrong or rotated token |
| `405` | Only POST is allowed |
| `413` | Over 1 MB as sent or 4 MB after decompression |
| `415` | Unknown `Content-Encoding` |
| `429` | Over 120 requests a minute for this token (`Retry-After: 60`), or the daily line limit is spent (`Retry-After` until 00:00 UTC) |

Errors are JSON: `{"error": "..."}`. The daily-limit 429 also carries `limit`, `retry_after` and `plans_url`.

## Limits and retries

- Lines longer than 8 KB are cut; NUL characters are replaced.
- When a batch is larger than what is left of today's quota, the lines that fit are stored and the rest are rejected (see `X-JustLog-Lines-Rejected`).
- On a network error or a 5xx, resend the same body with the same `X-JustLog-Session` and `X-JustLog-Seq`: if the first attempt did arrive, the server answers `202` with `X-JustLog-Repeat: 1` and does not store it twice.
- On 429, wait for `Retry-After` seconds. On 401, stop and ask for a new token.


# Telegram alerts

> Link a Telegram chat and get a message when a log session grows past a threshold or the daily quota runs low.

JustLog3 Cloud can message you in Telegram, so you hear about a runaway job or a spent quota without keeping the dashboard open. Alerts come from the bot [@justlog3cloud_bot](https://t.me/justlog3cloud_bot).

## Link a chat

1. Open the dashboard and find the **Telegram notifications** panel.
2. Click **Create secure link**. The link works once and expires in five minutes.
3. Open it in Telegram and press **Start**. The panel switches to *Connected*.

Your API token is never sent to Telegram: linking uses the one-time link only. To unlink, press **Disconnect** on the dashboard or send `/unconnect` to the bot.

## What you get alerts about

- **Session thresholds.** Every time one session (one run of your program, the `X-JustLog-Session` header) grows past another 100 lines, you get one message with the session and its line count. A loop that suddenly logs 50,000 lines is hard to miss.
- **Daily quota.** One message when 80% of today's log lines are used and one at 100%. After that, new lines are rejected until 00:00 UTC.
- **Plan renewal.** A reminder when a paid plan has expired and its 3-day grace period has started.

## Delivery

Alerts are queued with the logs that caused them and sent in the background, so sending logs never waits for Telegram. A message that fails is retried up to five times. If you block the bot or delete the chat, the chat is unlinked automatically.


# AI assistant

> Ask an assistant about your logs, tasks and GitHub repositories, and what it can and cannot do.

The AI assistant (**AI Assistant** in the dashboard) answers questions about your own data: why a run failed, what changed in a repository, which task to pick up next. It sees only what you switch on for a chat.

## Context you can switch on

| Switch | What the assistant gets |
|---|---|
| Logs | Your recent log lines, newest first; repeated lines are collapsed |
| Tasks | Your active tasks |
| GitHub | Recent commits, pull requests, checks and Actions runs of the repositories you picked |
| Memory | The facts you asked it to remember (see below) |

With a switch off, that data is not sent at all. Everything the assistant reads from logs, tasks, repositories and web pages is passed to the model as untrusted data, not as instructions, so a crafted log line can't take it over.

## Levels: Low, Medium, High

Under the message box you pick how hard the assistant works on the next reply:

| Level | Costs | What changes |
|---|---|---|
| Low | 1 message | A quick answer, the default |
| Medium | 2 messages | The model thinks it through first and gets 15% more context (logs, history, files, search results) |
| High | 4 messages | The deepest thinking, 30% more context and room for longer answers |

When the model reasons before it answers, the chat shows it as a folded **Thinking** block above the reply; open it to see how the answer was reached.

## What it can do

- **Explain and summarise** logs, stack traces and failed CI runs.
- **Read files and CI logs** of a selected GitHub repository when it needs them to answer; you see a "Reading ..." status while it does.
- **Search the web** on its own when an answer depends on current public information, such as a library release or an error message, and list the pages it used as sources under the reply. Searches a day: Free 3, Starter 15, Expert 50, Enterprise 100. Search queries never carry tokens, keys or email addresses.
- **Propose tasks**: create a task or mark one done. It only proposes; nothing changes until you press **Yes**.
- **Ask you a question** with a few answer buttons after it has answered, when your choice decides the next step. Pressing a button sends that answer as your next message.

## Memory

When you tell the assistant something lasting, such as your stack, a naming convention or how you like answers, it offers to remember it. A fact is saved only when you press **Yes**, and it is then shared by all your chats while the **Memory** switch is on. Open **Manage** next to the switch to see and delete facts; up to 30 are kept. Facts that look like passwords or keys are never saved.

## GitHub access

Connect GitHub from the dashboard. The JustLog3 GitHub App is read-only: contents, pull requests, checks and Actions. It can't push, merge or comment. You choose which repositories the assistant may read:

- Free: 1 repository
- Starter: 5 repositories
- Expert: 15 repositories
- Enterprise: 15 repositories

## Chats and limits

Chats are saved, so you can come back to one later, edit your last question or retry an answer. Long chats stay cheap: older turns are condensed into a short summary instead of being resent in full. Messages a day (reset at 00:00 UTC; a reply that fails costs nothing):

- Free: 12 a day
- Starter: 75 a day
- Expert: 400 a day
- Enterprise: unlimited

Answers stream as they are written. If one AI provider fails mid-answer, the next one takes over automatically.


# Plans and limits

> Daily log lines, retention, AI messages and repositories on Free, Starter, Expert and Enterprise.

Every plan has every feature; paid plans raise the limits. Prices are in US dollars and paid in crypto through NOWPayments. Nothing renews automatically. Compare plans and pay on the [plans page](https://jl3-cloud.site/plans/).

## Plans at a glance

| | Price | Log lines a day | Kept for | AI messages a day | Web searches a day | GitHub repositories |
|---|---|---|---|---|---|---|
| **Free** | Free | 5,000 | 2 days | 12 | 3 | 1 |
| **Starter** | $4.99 a month or $49.90 a year | 50,000 | 5, 7, 14 days | 75 | 15 | 5 |
| **Expert** | $20 a month or $200 a year | 300,000 | 5, 7, 14, 30 days | 400 | 50 | 15 |
| **Enterprise** | By agreement | Unlimited | Any, 90 days by default | Unlimited | 100 | 15 |

A yearly payment costs ten monthly ones. An AI reply on the Low level uses one message, Medium 2 and High 4; see [AI assistant](https://jl3-cloud.site/docs/ai-assistant/).

## AI credit packs

A busy day doesn't need a bigger plan: a credit pack adds AI credits on top of it, 100 for $2.00 or 300 for $5.00, paid once. Pack credits are spent only after the day's allowance runs out, never expire and stay when the plan changes. A reply is paid from one or the other, never split. Packs are on the [plans page](https://jl3-cloud.site/plans/#credits).

## Daily log lines

Counted per line of each request body and reset at 00:00 UTC. When a batch doesn't fit into what is left, the lines that fit are stored and the rest are rejected; then the API answers `429` with `Retry-After` until midnight. You get a Telegram message at 80% and 100%.

## Retention

Logs are kept for a sliding window and older lines are deleted every hour. Paid plans choose the window on the billing page.

## Request limits (all plans)

- 1 MB per request as sent, 4 MB after decompression.
- Lines over 8 KB are cut.
- 120 requests a minute per token.

## When a paid plan ends

A plan stays active for 3 more days after its end date, and you get a Telegram reminder. Then the account returns to Free, and logs older than Free's 2-day window are removed by the hourly cleanup.


# FAQ

> Answers to common questions about JustLog3 Cloud: pricing, data, security and troubleshooting.

## Is the Free plan actually free?

Yes. 5,000 log lines a day kept for 2 days, 12 assistant messages a day and 1 GitHub repository, with no card and no trial clock.

## Which languages are supported?

Python and Go have official libraries (`pip install justlog3`, `go get github.com/OAzizjon/justlog3/go`) that batch, retry and keep a local log file. Anything else that can send an HTTPS POST works through the [HTTP API](https://jl3-cloud.site/docs/http-api/): Node.js, Bash, PHP, a cron job or a Raspberry Pi.

## Do I need an agent or a config file?

No. A library call or a POST request is all it takes; there is no daemon to install.

## What happens when the cloud can't be reached?

The libraries keep writing your local log file, hold unsent lines in memory (up to 10,000 per logger) and resend them later with the same sequence number, so nothing is stored twice.

## Does the AI see all my data?

Only what you switch on for that chat: logs, tasks or GitHub. Everything it reads is treated as untrusted data, so a crafted log line can't take it over. See [AI assistant](https://jl3-cloud.site/docs/ai-assistant/).

## What can the GitHub integration touch?

Nothing it could break. The GitHub App is read-only: contents, pull requests, checks and Actions for the repositories you pick.

## How long are logs kept?

2 days on Free, 5 to 14 days on Starter and 5 to 30 days on Expert, chosen on the billing page. See [Plans and limits](https://jl3-cloud.site/docs/limits/).

## How do I pay?

In crypto through NOWPayments, monthly or yearly. Nothing renews automatically: when a plan ends it keeps working for 3 more days, and you get a Telegram reminder.

## Nothing shows up in my logs. What should I check?

- The URL: the libraries send to JustLog3 Cloud by default; a `url=` (Python) or `WithURL` (Go) pointing somewhere else sends your logs there instead.
- `401 Unauthorized`: the token is wrong or was rotated. Set the current token and restart.
- `429 Too Many Requests`: today's line limit is spent or the client sends more than 120 requests a minute.
- Go: make sure `justlog3.Shutdown()` runs; `log.Fatal` and `os.Exit` skip deferred calls.
