Attaching Logs
Send job output alongside your pings so you can inspect what happened directly in the dashboard.
Overview
All Cronping ping endpoints accept an optional request body when you use POST. The body is stored alongside the ping event (up to 100 KB) and is visible in the ping history in the dashboard.
This is useful for:
- Attaching the output of a backup or maintenance script
- Capturing error messages when a job fails
- Recording metrics or summaries without a separate logging pipeline
Capturing command output in a shell script
Capture stdout and stderr into a variable, then POST it as the request body:
#!/bin/sh
m=$(/usr/bin/backup.sh 2>&1)
curl -fsS -m 10 --data-raw "$m" https://ping.cronping.com/<token>Signal success or failure based on the exit code
#!/bin/sh
m=$(/usr/bin/backup.sh 2>&1)
curl -fsS -m 10 --data-raw "$m" https://ping.cronping.com/<token>/$?Exit code 0 → success ping. Any other value → failure ping. The captured output is attached either way.
Output is too large for --data-raw
If the command produces a lot of output you may get an "Argument list too long" error. Use a temp file instead:
#!/bin/sh
/usr/bin/backup.sh > /tmp/backup.log 2>&1
curl -fsS -m 10 --data-binary @/tmp/backup.log https://ping.cronping.com/<token>/$?Sending logs without changing status
Use the /log endpoint to attach a log entry without altering the heartbeat's current status. Cronping records the event but leaves the heartbeat state unchanged.
curl -fsS -m 10 \
--data-raw "Processed 1,423 records in 8.3s" \
https://ping.cronping.com/<token>/logThis is useful for attaching progress updates or mid-job diagnostics.
Language examples
Python
import urllib.request
import subprocess
result = subprocess.run(
["/usr/bin/backup.sh"],
capture_output=True,
text=True,
)
output = (result.stdout + result.stderr).encode()
action = str(result.returncode) # "0" = success, anything else = failure
req = urllib.request.Request(
f"https://ping.cronping.com/<token>/{action}",
data=output[:100_000],
method="POST",
)
try:
urllib.request.urlopen(req, timeout=10)
except Exception as e:
print(f"Cronping ping failed: {e}")Node.js
const { execSync } = require("child_process");
let output = "";
let exitCode = 0;
try {
output = execSync("/usr/bin/backup.sh", { stdio: "pipe" }).toString();
} catch (err) {
output = err.stdout?.toString() + err.stderr?.toString();
exitCode = err.status ?? 1;
}
try {
await fetch(`https://ping.cronping.com/<token>/${exitCode}`, {
method: "POST",
body: output.slice(0, 100_000),
signal: AbortSignal.timeout(10_000),
});
} catch (err) {
console.error("Cronping ping failed:", err.message);
}Go
package main
import (
"bytes"
"fmt"
"net/http"
"os/exec"
"strconv"
"time"
)
func main() {
out, err := exec.Command("/usr/bin/backup.sh").CombinedOutput()
exitCode := 0
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
exitCode = exitErr.ExitCode()
} else {
exitCode = 1
}
}
body := out
if len(body) > 100_000 {
body = body[:100_000]
}
client := &http.Client{Timeout: 10 * time.Second}
url := "https://ping.cronping.com/<token>/" + strconv.Itoa(exitCode)
resp, pingErr := client.Post(url, "text/plain", bytes.NewReader(body))
if pingErr != nil {
fmt.Printf("Cronping ping failed: %v\n", pingErr)
return
}
defer resp.Body.Close()
}C#
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
static readonly HttpClient _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };
static async Task RunJobAndPingAsync(string token)
{
var process = new Process
{
StartInfo = new ProcessStartInfo("/usr/bin/backup.sh")
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
}
};
process.Start();
string output = await process.StandardOutput.ReadToEndAsync()
+ await process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
int exitCode = process.ExitCode;
try
{
var content = new StringContent(
output.Length > 100_000 ? output[..100_000] : output,
Encoding.UTF8,
"text/plain"
);
using var _ = await _httpClient.PostAsync(
$"https://ping.cronping.com/{token}/{exitCode}",
content
);
}
catch (Exception ex)
{
Console.Error.WriteLine($"Cronping ping failed: {ex.Message}");
}
}Size limit
Cronping stores up to 100 KB per ping. If your job output is larger:
- Trim verbose output and send only a summary (row counts, durations, errors).
- Send the last 100 KB, which usually contains the most relevant output:
m=$(/usr/bin/backup.sh 2>&1 | tail -c 100000)
curl -fsS -m 10 --data-raw "$m" https://ping.cronping.com/<token>/$?- For full log retention, pipe output to a dedicated log service (Loki, Datadog, etc.) and use Cronping only for status signals.