fix: add detailed watch-order logs
This commit is contained in:
@@ -50,8 +50,21 @@ func (c *Client) getWatchOrder(ctx context.Context, id int) (watchorder.WatchOrd
|
|||||||
|
|
||||||
result, err := watchorder.FetchWatchOrder(requestCtx, c.httpClient, watchOrderURL)
|
result, err := watchorder.FetchWatchOrder(requestCtx, c.httpClient, watchOrderURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var statusError *watchorder.HTTPStatusError
|
||||||
if errors.Is(err, watchorder.ErrWatchOrderMarkupNotFound) {
|
if errors.Is(err, watchorder.ErrWatchOrderMarkupNotFound) {
|
||||||
log.Printf("relations: watch-order markup missing for %d (%s): %v", id, watchOrderURL, err)
|
log.Printf("relations: watch-order markup missing for %d (%s): %v", id, watchOrderURL, err)
|
||||||
|
} else if errors.As(err, &statusError) {
|
||||||
|
log.Printf(
|
||||||
|
"relations: watch-order http error for %d (%s): status=%d server=%q cf_ray=%q location=%q content_type=%q body=%q",
|
||||||
|
id,
|
||||||
|
watchOrderURL,
|
||||||
|
statusError.StatusCode,
|
||||||
|
statusError.Server,
|
||||||
|
statusError.CFRay,
|
||||||
|
statusError.Location,
|
||||||
|
statusError.ContentType,
|
||||||
|
statusError.BodyPreview,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("relations: watch-order fetch failed for %d (%s): %v", id, watchOrderURL, err)
|
log.Printf("relations: watch-order fetch failed for %d (%s): %v", id, watchOrderURL, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -19,6 +20,29 @@ var idPattern = regexp.MustCompile(`/id/(\d+)`)
|
|||||||
var ErrInvalidWatchOrderURL = errors.New("invalid watch order url")
|
var ErrInvalidWatchOrderURL = errors.New("invalid watch order url")
|
||||||
var ErrWatchOrderMarkupNotFound = errors.New("watch order markup not found")
|
var ErrWatchOrderMarkupNotFound = errors.New("watch order markup not found")
|
||||||
|
|
||||||
|
type HTTPStatusError struct {
|
||||||
|
StatusCode int
|
||||||
|
URL string
|
||||||
|
Server string
|
||||||
|
CFRay string
|
||||||
|
Location string
|
||||||
|
ContentType string
|
||||||
|
BodyPreview string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HTTPStatusError) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"unexpected status code: %d (url=%s server=%s cf_ray=%s location=%s content_type=%s body=%q)",
|
||||||
|
e.StatusCode,
|
||||||
|
e.URL,
|
||||||
|
e.Server,
|
||||||
|
e.CFRay,
|
||||||
|
e.Location,
|
||||||
|
e.ContentType,
|
||||||
|
e.BodyPreview,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
type WatchOrderEntry struct {
|
type WatchOrderEntry struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
@@ -76,7 +100,16 @@ func fetchDocument(ctx context.Context, httpClient *http.Client, url string) (*g
|
|||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != http.StatusOK {
|
||||||
return nil, fmt.Errorf("unexpected status code: %d", response.StatusCode)
|
body, _ := io.ReadAll(io.LimitReader(response.Body, 512))
|
||||||
|
return nil, &HTTPStatusError{
|
||||||
|
StatusCode: response.StatusCode,
|
||||||
|
URL: url,
|
||||||
|
Server: strings.TrimSpace(response.Header.Get("Server")),
|
||||||
|
CFRay: strings.TrimSpace(response.Header.Get("CF-Ray")),
|
||||||
|
Location: strings.TrimSpace(response.Header.Get("Location")),
|
||||||
|
ContentType: strings.TrimSpace(response.Header.Get("Content-Type")),
|
||||||
|
BodyPreview: strings.Join(strings.Fields(strings.TrimSpace(string(body))), " "),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document, err := goquery.NewDocumentFromReader(response.Body)
|
document, err := goquery.NewDocumentFromReader(response.Body)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -125,3 +126,35 @@ func TestFetchWatchOrder_MissingMarkupReturnsError(t *testing.T) {
|
|||||||
t.Fatalf("expected ErrWatchOrderMarkupNotFound, got %v", err)
|
t.Fatalf("expected ErrWatchOrderMarkupNotFound, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFetchWatchOrder_HTTPStatusErrorIncludesContext(t *testing.T) {
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Server", "cloudflare")
|
||||||
|
w.Header().Set("CF-Ray", "abc123")
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
_, _ = w.Write([]byte("<html><body>access denied</body></html>"))
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
url := server.URL + "/?/tools/watch_order/id/1"
|
||||||
|
_, err := FetchWatchOrder(context.Background(), &http.Client{Timeout: time.Second}, url)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusError *HTTPStatusError
|
||||||
|
if !errors.As(err, &statusError) {
|
||||||
|
t.Fatalf("expected HTTPStatusError, got %T", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusError.StatusCode != http.StatusForbidden {
|
||||||
|
t.Fatalf("expected 403, got %d", statusError.StatusCode)
|
||||||
|
}
|
||||||
|
if statusError.CFRay != "abc123" {
|
||||||
|
t.Fatalf("expected cf-ray abc123, got %q", statusError.CFRay)
|
||||||
|
}
|
||||||
|
if !strings.Contains(statusError.BodyPreview, "access denied") {
|
||||||
|
t.Fatalf("expected body preview to include access denied, got %q", statusError.BodyPreview)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user