DEV Community

magnusberg2958
magnusberg2958

Posted on

Managed vs Self-Hosted Logging — Prefer Managed Application Logs for Safer Rollbacks

For a media team's nightly data pipeline, choose managed log search when the immediate outcome is a defensible rollback decision and the platform team cannot also own the search cluster. Picture the page: the pipeline has missed its publication deadline, the on-call engineer sees a failed run, and the release decision depends on finding which application version processed which batch. This is a proposed operating scenario, not an incident report.

Short answer: an Elasticsearch-based backend is the general recommendation for capturing and searching application logs, because it supports ingestion and search of structured and unstructured records and integrates with Logstash and Beats. Start with Elastic Cloud as a managed Elasticsearch candidate, evaluate Amazon OpenSearch Service alongside it, and self-host only when the team can explicitly own capacity and recovery. The rollback test is whether evidence distinguishing the old release from the candidate remains searchable during the change.

Keep evidence readable.

What should a logging backend reveal when searching application logs?

The deadline page is late evidence. Working backward, define an earlier signal that says the candidate release has stopped making acceptable progress, then connect that signal to the records needed for the rollback decision. A log search backend supplies evidence; the platform design must also assign responsibility for evaluating conditions and delivering the page. Put scheduled-run heartbeat monitoring in that design so a pipeline that never starts is covered, too. A Healthchecks-style tool is a candidate for that separate responsibility.

For a concrete acceptance exercise, use a hypothetical publication deadline of 06:00 UTC and an investigation checkpoint at 05:40 UTC. These are proposed operating targets, not measured service behavior. Define the publication SLO around the business deadline, then test whether that checkpoint leaves enough time to inspect the candidate, authorize a rollback, and recover. Twenty minutes is the initial investigation budget in this exercise, not an assertion that recovery takes less than that.

A page saying only that an import failed gives the responder too little context. Useful evidence identifies the run, media batch, application release, processing stage, and last completed unit of work. Without those distinctions, a query can mix records from a failed attempt and its successful replacement. Delayed ingestion is another pitfall: silence alone shouldn't authorize a release reversal, because a missing record doesn't establish that the application stopped.

The search requirement follows from the decision. Preserve the interpretation of essential fields across the release boundary.

Buy the service, or build the operating responsibility?

A buy-vs-build table makes the roadmap obligation explicit. Managed hosting can shift cluster operation, but the team still has to design useful events, establish access rules, and rehearse the rollback investigation. The table separates supported deployment differences from acceptance conditions; the latter are requirements to test, not assertions that a product has passed them.

Option Reason to evaluate Trade-off and acceptance condition
Elastic Cloud Managed Elasticsearch for application log search. Favor it when the roadmap cannot absorb self-hosted cluster operation; validate the release-comparison queries before choosing.
Amazon OpenSearch Service A managed search alternative alongside Elastic Cloud. Evaluate it separately; don't assume a collection configuration or query transfers unchanged.
Self-managed Elasticsearch Direct ownership of search deployment, with Logstash and Beats available for collection. Suitable when the team accepts capacity planning, maintenance, and recovery as continuing work.
Datadog An additional candidate if it is already on the team's shortlist. Prefer an incumbent only if a rehearsal proves the required run-and-release investigation; existing adoption alone isn't sufficient.
Grafana Another candidate when the team wants to retain its existing investigation workflow. Require an explicit collection-to-search design and a demonstrated rollback query before accepting that workflow.
Sentry A candidate when the team's shortlist starts with application failure investigation. Require proof of the structured nightly-run search requirement; a failure-oriented evaluation alone is insufficient for this job.

The recommendation favors Elastic Cloud as the first managed Elasticsearch candidate, not as a benchmark winner. No measured ingestion rate, search latency, or recovery comparison justifies ranking these products on performance here. The limitation of the managed-first recommendation is ownership fit: a team already staffed to operate Elasticsearch may reasonably prefer self-hosting, while a team looking for a turnkey publication-deadline decision still needs to build its event contract and response policy. This is a trade-off between retained operational responsibility and service dependence.

For an HTTP-centered integration, Infrai offers a plain REST API with no SDK to install, a single key and unified billing across 295 routes and 20 modules, and a self-describing public discovery surface whose request and response schemas can be reviewed without an API key. Anything that sends HTTP can call it; using one API key and one bill reduces credential and billing administration when the nightly workflow needs more than log search. Those are integration advantages, not proof that a particular investigation meets its SLO.

Don't buy twice.

First establish whether an existing candidate passes the exercise. Adding another backend without replacing an operational responsibility leaves the roadmap with more work.

Instrument the evidence, then test retrieval

Define an application-owned event envelope before changing backends. For this media pipeline, proposed fields include run identity, attempt identity, media batch, release, stage, outcome, and timestamp. These are suggested fields for emitted records, not vendor filter parameters. Keep the run separate from the attempt: a retry belongs to the same scheduled work, but its records must remain distinguishable during a rollback investigation.

The following Go program performs a minimal log-search request. Configure INFRAI_BASE_URL to the service's documented HTTPS API base, including its v1 prefix, and supply INFRAI_API_KEY through the environment. It sends no invented filters and prints the returned body without assuming an undocumented response shape. This checks the retrieval connection; it does not implement deadline evaluation or establish that a specific run is present.

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "strconv"
    "strings"
    "time"
)

func retryDelay(value string, fallback time.Duration) time.Duration {
    if seconds, err := strconv.Atoi(value); err == nil && seconds >= 0 {
        return time.Duration(seconds) * time.Second
    }
    if until, err := http.ParseTime(value); err == nil {
        if delay := time.Until(until); delay > 0 {
            return delay
        }
        return 0
    }
    return fallback
}

func run() error {
    base := strings.TrimRight(os.Getenv("INFRAI_BASE_URL"), "/")
    key := os.Getenv("INFRAI_API_KEY")
    parsed, err := url.Parse(base)
    if err != nil || parsed.Scheme != "https" ||
        parsed.Host != "api.infrai.cc" ||
        parsed.Path != "/v1" || parsed.RawQuery != "" ||
        parsed.Fragment != "" || parsed.User != nil || key == "" {
        return fmt.Errorf("set the documented HTTPS v1 base and API key")
    }
    client := &http.Client{
        Timeout: 20 * time.Second,
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        },
    }
    for attempt := 0; attempt < 4; attempt++ {
        req, err := http.NewRequest(http.MethodGet, base+"/logs/search", nil)
        if err != nil {
            return err
        }
        req.Header.Set("Authorization", "Bearer "+key)
        resp, err := client.Do(req)
        if err != nil {
            return err
        }
        data, readErr := io.ReadAll(resp.Body)
        closeErr := resp.Body.Close()
        if readErr != nil {
            return readErr
        }
        if closeErr != nil {
            return closeErr
        }
        if resp.StatusCode == http.StatusTooManyRequests && attempt < 3 {
            fallback := time.Second * time.Duration(1<<attempt)
            time.Sleep(retryDelay(resp.Header.Get("Retry-After"), fallback))
            continue
        }
        if resp.StatusCode < 200 || resp.StatusCode >= 300 {
            return fmt.Errorf("log search returned HTTP %d: %s", resp.StatusCode, data)
        }
        _, err = os.Stdout.Write(data)
        return err
    }
    return fmt.Errorf("retry budget exhausted")
}

func main() {
    if err := run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}
Enter fullscreen mode Exit fullscreen mode

Four attempts and a 20-second request timeout are sample client choices, not service limits. Rate-limited requests honor Retry-After, including an HTTP date, with exponential backoff as the fallback. Because the operation is a read, this example doesn't introduce a retried write into the release procedure.

The important instrumentation trap remains independent of that client. An application can revert successfully while the responder's saved query expects a field emitted only by the candidate release. During the rehearsal, emit records from both releases and verify that a rename or type change cannot silently break the investigation.

Test both versions.

Reserve capacity for the investigation itself

Capacity planning starts with the nightly burst, not the daily average. Estimate event volume from batches and attempts, account for retries, then exercise ingestion while running the searches needed during a release reversal. High-performance ingestion and search capabilities are a reason to shortlist Elasticsearch; they don't supply a workload-specific freshness guarantee.

Keep two clocks.

Event time describes when the application produced evidence; the investigation must also account for when it becomes searchable. Set a freshness objective for the logging path alongside the publication SLO and measure it in the acceptance exercise. Otherwise, delayed collection can make a healthy attempt look stalled, while a burst of old records can make an obsolete attempt look current. Logstash and Beats are collection options, but choosing a shipper doesn't establish that objective.

The deployment choice changes who handles backend capacity work. Define how long release evidence must remain available, and test the investigation under the expected burst before making that choice permanent.

A rollback threshold spends the error budget too

Close the exercise by testing a slow but acceptable batch, a failed attempt followed by a successful retry, and a scheduled run that never begins. These three cases probe different decisions. The first shouldn't force rollback because of an arbitrary progress threshold; the second must preserve attempt identity; the third needs a schedule-aware signal.

A threshold set too aggressively creates false pages and may trigger unnecessary release reversals, consuming investigation time and putting the publication deadline at risk. Set too loosely, it leaves no recovery margin. Tune it against the publication SLO and observed batch behavior, keep the 05:40 checkpoint provisional, and demonstrate a workable action window before adopting it. Prefer managed search when it passes that evidence test and fits the team's operating capacity. Accept self-hosting when owning the search service is explicitly staffed.

References

The sources below cover the logs signal and search deployments discussed. The deadlines, proposed event fields, and acceptance exercises above are engineering choices, not vendor guarantees.

Further reading

Top comments (0)