func (a *App) serveTrace(w http.ResponseWriter, r *http.Request) error { v := mux.Vars(r) traceID, err := appdash.ParseID(v["Trace"]) if err != nil { return err } trace, err := a.Store.Trace(traceID) if err != nil { return err } // Get sub-span if the Span route var is present. if spanIDStr := v["Span"]; spanIDStr != "" { spanID, err := appdash.ParseID(spanIDStr) if err != nil { return err } trace = trace.FindSpan(spanID) if trace == nil { return errors.New("could not find the specified trace span") } } // We could use a separate handler for this, but as we need the above to // determine the correct trace (or therein sub-trace), we just handle any // JSON profile requests here. if path.Base(r.URL.Path) == "profile" { return a.profile(trace, w) } visData, err := a.d3timeline(trace) if err != nil { return err } // Determine the profile URL. var profile *url.URL if trace.ID.Parent == 0 { profile, err = a.Router.URLToTraceProfile(trace.Span.ID.Trace) } else { profile, err = a.Router.URLToTraceSpanProfile(trace.Span.ID.Trace, trace.Span.ID.Span) } if err != nil { return err } return a.renderTemplate(w, r, "trace.html", http.StatusOK, &struct { TemplateCommon Trace *appdash.Trace VisData []timelineItem ProfileURL string }{ Trace: trace, VisData: visData, ProfileURL: profile.String(), }) }
func (a *App) serveTraces(w http.ResponseWriter, r *http.Request) error { // Parse the query for a comma-separated list of traces that we should only // show (all others are hidden). var showJust []appdash.ID if show := r.URL.Query().Get("show"); len(show) > 0 { for _, idStr := range strings.Split(show, ",") { id, err := appdash.ParseID(idStr) if err == nil { showJust = append(showJust, id) } } } traces, err := a.Queryer.Traces(appdash.TracesOpts{ TraceIDs: showJust, }) if err != nil { return err } return a.renderTemplate(w, r, "traces.html", http.StatusOK, &struct { TemplateCommon Traces []*appdash.Trace Visible func(*appdash.Trace) bool }{ Traces: traces, Visible: func(t *appdash.Trace) bool { return true }, }) }
func (a *App) serveTraces(w http.ResponseWriter, r *http.Request) error { traces, err := a.Queryer.Traces() if err != nil { return err } // Parse the query for a comma-separated list of traces that we should only // show (all others are hidden). var showJust []appdash.ID if show := r.URL.Query().Get("show"); len(show) > 0 { for _, idStr := range strings.Split(show, ",") { id, err := appdash.ParseID(idStr) if err == nil { showJust = append(showJust, id) } } } // Sort the traces by ID to ensure that the display order doesn't change upon // multiple page reloads if Queryer.Traces is e.g. backed by a map (which has // a random iteration order). sort.Sort(tracesByID(traces)) return a.renderTemplate(w, r, "traces.html", http.StatusOK, &struct { TemplateCommon Traces []*appdash.Trace Visible func(*appdash.Trace) bool }{ Traces: traces, Visible: func(t *appdash.Trace) bool { // Hide the traces that contain aggregate events (that's all they have, so // they are not very useful to users). if t.IsAggregate() { return false } if len(showJust) > 0 { // Showing just a few traces. for _, id := range showJust { if id == t.Span.ID.Trace { return true } } return false } return true }, }) }
func (a *App) serveAggregate(w http.ResponseWriter, r *http.Request) error { // By default we display all traces. traces, err := a.Queryer.Traces() if err != nil { return err } q := r.URL.Query() // If they specified a comma-separated list of specific trace IDs that they // are interested in, then we only show those. selection := q.Get("selection") if len(selection) > 0 { var selected []*appdash.Trace for _, idStr := range strings.Split(selection, ",") { id, err := appdash.ParseID(idStr) if err != nil { return err } for _, t := range traces { if t.Span.ID.Trace == id { selected = append(selected, t) } } } traces = selected } // Perform the aggregation and render the data. aggregated, err := a.aggregate(traces, parseAggMode(q.Get("view-mode"))) if err != nil { return err } return a.renderTemplate(w, r, "aggregate.html", http.StatusOK, &struct { TemplateCommon Aggregated []*aggItem }{ Aggregated: aggregated, }) }
func (a *App) serveTrace(w http.ResponseWriter, r *http.Request) error { v := mux.Vars(r) traceID, err := appdash.ParseID(v["Trace"]) if err != nil { return err } trace, err := a.Store.Trace(traceID) if err != nil { return err } // Get sub-span if the Span route var is present. if spanIDStr := v["Span"]; spanIDStr != "" { spanID, err := appdash.ParseID(spanIDStr) if err != nil { return err } trace = trace.FindSpan(spanID) if trace == nil { return errors.New("could not find the specified trace span") } } // We could use a separate handler for this, but as we need the above to // determine the correct trace (or therein sub-trace), we just handle any // JSON profile requests here. if path.Base(r.URL.Path) == "profile" { return a.profile(trace, w) } // Do not show d3 timeline chart when timeline item fields are invalid. // So we avoid JS code breaking due missing values. var showTimelineChart bool = true visData, err := a.d3timeline(trace) switch err { case ErrTimelineItemValidation: showTimelineChart = false case nil: break default: return err } // Determine the profile URL. var profile *url.URL if trace.ID.Parent == 0 { profile, err = a.Router.URLToTraceProfile(trace.Span.ID.Trace) } else { profile, err = a.Router.URLToTraceSpanProfile(trace.Span.ID.Trace, trace.Span.ID.Span) } if err != nil { return err } return a.renderTemplate(w, r, "trace.html", http.StatusOK, &struct { TemplateCommon Trace *appdash.Trace ShowTimelineChart bool VisData []timelineItem ProfileURL string }{ Trace: trace, ShowTimelineChart: showTimelineChart, VisData: visData, ProfileURL: profile.String(), }) }
func (a *App) serveTrace(w http.ResponseWriter, r *http.Request) error { v := mux.Vars(r) if permalink := r.URL.Query().Get("permalink"); permalink != "" { // If the user specified a permalink, then decode it directly into a // trace structure and place it into storage for viewing. gz, err := gzip.NewReader(base64.NewDecoder(base64.RawURLEncoding, strings.NewReader(permalink))) if err != nil { return err } var upload *appdash.Trace if err := json.NewDecoder(gz).Decode(&upload); err != nil { return err } if err := a.uploadTraces(upload); err != nil { return err } } // Look in the store for the trace. traceID, err := appdash.ParseID(v["Trace"]) if err != nil { return err } trace, err := a.Store.Trace(traceID) if err != nil { return err } // Get sub-span if the Span route var is present. if spanIDStr := v["Span"]; spanIDStr != "" { spanID, err := appdash.ParseID(spanIDStr) if err != nil { return err } trace = trace.FindSpan(spanID) if trace == nil { return errors.New("could not find the specified trace span") } } // We could use a separate handler for this, but as we need the above to // determine the correct trace (or therein sub-trace), we just handle any // JSON profile requests here. if path.Base(r.URL.Path) == "profile" { return a.profile(trace, w) } // Do not show d3 timeline chart when timeline item fields are invalid. // So we avoid JS code breaking due missing values. var showTimelineChart bool = true visData, err := a.d3timeline(trace) switch err { case errTimelineItemValidation: showTimelineChart = false case nil: break default: return err } // Determine the profile URL. var profile *url.URL if trace.ID.Parent == 0 { profile, err = a.Router.URLToTraceProfile(trace.Span.ID.Trace) } else { profile, err = a.Router.URLToTraceSpanProfile(trace.Span.ID.Trace, trace.Span.ID.Span) } if err != nil { return err } // The JSON trace is the human-readable trace form for exporting. jsonTrace, err := json.MarshalIndent([]*appdash.Trace{trace}, "", " ") if err != nil { return err } // The permalink of the trace is literally the JSON encoded trace gzipped & base64 encoded. var buf bytes.Buffer gz := gzip.NewWriter(base64.NewEncoder(base64.RawURLEncoding, &buf)) err = json.NewEncoder(gz).Encode(trace) if err != nil { return err } if err := gz.Close(); err != nil { return err } permalink, err := a.URLToTrace(trace.ID.Trace) if err != nil { return err } permalink.RawQuery = "permalink=" + buf.String() return a.renderTemplate(w, r, "trace.html", http.StatusOK, &struct { TemplateCommon Trace *appdash.Trace ShowTimelineChart bool VisData []timelineItem ProfileURL string Permalink string JSONTrace string }{ Trace: trace, ShowTimelineChart: showTimelineChart, VisData: visData, ProfileURL: profile.String(), Permalink: permalink.String(), JSONTrace: string(jsonTrace), }) }