> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitors history

### monitors\_history

Find full example [here](https://github.com/getsynq/api/tree/main/examples/golang/monitors_history)

#### main.go

```go theme={null}
package main

import (
	"context"
	"crypto/tls"
	"flag"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	historyv1grpc "buf.build/gen/go/getsynq/api/grpc/go/synq/monitors/history/v1/historyv1grpc"
	historyv1 "buf.build/gen/go/getsynq/api/protocolbuffers/go/synq/monitors/history/v1"
	"golang.org/x/oauth2/clientcredentials"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/credentials/oauth"
	"google.golang.org/protobuf/types/known/timestamppb"
)

// Fetches prediction history for one monitor.
//
// Flags win over env vars of the same name.
//
// Required:
//
//	-client-id / SYNQ_CLIENT_ID, -client-secret / SYNQ_CLIENT_SECRET  — SCOPE_MONITORS_READ
//	-monitor-path / MONITOR_PATH  — e.g. monitor::ch-prod::default::runs::volume
//
// Optional:
//
//	-endpoint / API_ENDPOINT     — developer.synq.io (EU, default), api.us.synq.io (US), api.au.synq.io (AU)
//	-metrics-version / METRICS_VERSION  — default 1
//	-from / FROM, -to / TO       — RFC3339 (default: last 7 days → now)
//	-segments / SEGMENTS         — comma-separated; empty string is the unsegmented series.
//	                               omit to return all segments
func main() {
	clientID := flag.String("client-id", os.Getenv("SYNQ_CLIENT_ID"), "OAuth client id (SYNQ_CLIENT_ID)")
	clientSecret := flag.String("client-secret", os.Getenv("SYNQ_CLIENT_SECRET"), "OAuth client secret (SYNQ_CLIENT_SECRET)")
	monitorPath := flag.String("monitor-path", os.Getenv("MONITOR_PATH"), "monitor synq path (MONITOR_PATH)")
	host := flag.String("endpoint", envOr("API_ENDPOINT", "developer.synq.io"), "API host without port (API_ENDPOINT)")
	metricsVersion := flag.Int("metrics-version", envInt("METRICS_VERSION", 1), "metrics version (METRICS_VERSION)")
	fromRaw := flag.String("from", os.Getenv("FROM"), "RFC3339 start (FROM); default now-7d")
	toRaw := flag.String("to", os.Getenv("TO"), "RFC3339 end (TO); default now")
	segmentsRaw := flag.String("segments", os.Getenv("SEGMENTS"), "comma-separated segments (SEGMENTS); omit for all")
	flag.Parse()

	segmentsSet := envSet("SEGMENTS")
	flag.Visit(func(f *flag.Flag) {
		if f.Name == "segments" {
			segmentsSet = true
		}
	})

	if *clientID == "" || *clientSecret == "" {
		panic("-client-id / SYNQ_CLIENT_ID and -client-secret / SYNQ_CLIENT_SECRET must be set")
	}
	if *monitorPath == "" {
		panic("-monitor-path / MONITOR_PATH must be set (e.g. monitor::<asset_path>::volume)")
	}

	to := time.Now().UTC()
	from := to.Add(-7 * 24 * time.Hour)
	if *fromRaw != "" {
		t, err := time.Parse(time.RFC3339, *fromRaw)
		if err != nil {
			panic(fmt.Sprintf("-from: %v", err))
		}
		from = t
	}
	if *toRaw != "" {
		t, err := time.Parse(time.RFC3339, *toRaw)
		if err != nil {
			panic(fmt.Sprintf("-to: %v", err))
		}
		to = t
	}

	var segments []string
	if segmentsSet {
		segments = strings.Split(*segmentsRaw, ",")
	}

	ctx := context.Background()
	apiURL := fmt.Sprintf("%s:443", *host)
	tokenURL := fmt.Sprintf("https://%s/oauth2/token", *host)

	oauthTokenSource := oauth.TokenSource{TokenSource: (&clientcredentials.Config{
		ClientID:     *clientID,
		ClientSecret: *clientSecret,
		TokenURL:     tokenURL,
	}).TokenSource(ctx)}

	conn, err := grpc.NewClient(apiURL,
		grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
		grpc.WithPerRPCCredentials(oauthTokenSource),
		grpc.WithAuthority(*host),
	)
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	fmt.Printf("Connected to %s\n", *host)

	resp, err := historyv1grpc.NewHistoryServiceClient(conn).History(ctx, &historyv1.HistoryRequest{
		MonitorPath:    *monitorPath,
		MetricsVersion: int32(*metricsVersion),
		Segments:       segments,
		From:           timestamppb.New(from),
		To:             timestamppb.New(to),
	})
	if err != nil {
		panic(err)
	}

	fmt.Printf("monitor=%s version=%d from=%s to=%s predictions=%d\n",
		*monitorPath, *metricsVersion, from.Format(time.RFC3339), to.Format(time.RFC3339), len(resp.Predictions))

	for i, p := range resp.Predictions {
		vu, vl := "nil", "nil"
		if p.Vu != nil {
			vu = fmt.Sprintf("%.6g", p.Vu.Value)
		}
		if p.Vl != nil {
			vl = fmt.Sprintf("%.6g", p.Vl.Value)
		}
		fmt.Printf("%d  t=%s  m=%s  s=%q  v=%.6g  e=%.6g  st=%.6g  vl=%s  vu=%s  p=%s  f=%s\n",
			i, p.T.AsTime().UTC().Format(time.RFC3339), p.M, p.S, p.V, p.E, p.St, vl, vu, p.P, p.F)
	}
}

func envOr(key, fallback string) string {
	if v := os.Getenv(key); v != "" {
		return v
	}
	return fallback
}

func envSet(key string) bool {
	_, ok := os.LookupEnv(key)
	return ok
}

func envInt(key string, fallback int) int {
	raw := os.Getenv(key)
	if raw == "" {
		return fallback
	}
	n, err := strconv.Atoi(raw)
	if err != nil {
		panic(fmt.Sprintf("%s: %v", key, err))
	}
	return n
}
```
