github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/api/handlers/libpod/containers_stats.go (about)

     1  package libpod
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  	"time"
     7  
     8  	"github.com/containers/podman/v2/libpod"
     9  	"github.com/containers/podman/v2/pkg/api/handlers/utils"
    10  	"github.com/containers/podman/v2/pkg/domain/entities"
    11  	"github.com/containers/podman/v2/pkg/domain/infra/abi"
    12  	"github.com/gorilla/schema"
    13  	"github.com/pkg/errors"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  const DefaultStatsPeriod = 5 * time.Second
    18  
    19  func StatsContainer(w http.ResponseWriter, r *http.Request) {
    20  	runtime := r.Context().Value("runtime").(*libpod.Runtime)
    21  	decoder := r.Context().Value("decoder").(*schema.Decoder)
    22  
    23  	query := struct {
    24  		Containers []string `schema:"containers"`
    25  		Stream     bool     `schema:"stream"`
    26  	}{
    27  		Stream: true,
    28  	}
    29  	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
    30  		utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
    31  		return
    32  	}
    33  
    34  	// Reduce code duplication and use the local/abi implementation of
    35  	// container stats.
    36  	containerEngine := abi.ContainerEngine{Libpod: runtime}
    37  
    38  	statsOptions := entities.ContainerStatsOptions{
    39  		Stream: query.Stream,
    40  	}
    41  
    42  	// Stats will stop if the connection is closed.
    43  	statsChan, err := containerEngine.ContainerStats(r.Context(), query.Containers, statsOptions)
    44  	if err != nil {
    45  		utils.InternalServerError(w, err)
    46  		return
    47  	}
    48  
    49  	// Write header and content type.
    50  	w.WriteHeader(http.StatusOK)
    51  	w.Header().Add("Content-Type", "application/json")
    52  	if flusher, ok := w.(http.Flusher); ok {
    53  		flusher.Flush()
    54  	}
    55  
    56  	// Setup JSON encoder for streaming.
    57  	coder := json.NewEncoder(w)
    58  	coder.SetEscapeHTML(true)
    59  
    60  	for stats := range statsChan {
    61  		if err := coder.Encode(stats); err != nil {
    62  			// Note: even when streaming, the stats goroutine will
    63  			// be notified (and stop) as the connection will be
    64  			// closed.
    65  			logrus.Errorf("Unable to encode stats: %v", err)
    66  			return
    67  		}
    68  		if flusher, ok := w.(http.Flusher); ok {
    69  			flusher.Flush()
    70  		}
    71  	}
    72  }