Ejemplo n.º 1
0
    def get(self, request):
        charts = []

        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD,
                           discover_total_period))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD,
                           discover_multi_y_axis))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD,
                           discover_empty))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_DAILY,
                           discover_total_daily))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_DAILY,
                           discover_total_daily_multi))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_DAILY,
                           discover_empty))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOP5_PERIOD,
                           discover_top5))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOP5_PERIOD,
                           discover_empty))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOP5_DAILY, discover_top5))
        charts.append(
            generate_chart(ChartType.SLACK_DISCOVER_TOP5_DAILY,
                           discover_empty))

        return render_to_response("sentry/debug/chart-renderer.html",
                                  context={"charts": charts})
Ejemplo n.º 2
0
    def test_simple(self, mock_uuid):
        mock_uuid.return_value = self.get_mock_uuid()

        chart_data = {
            "seriesName": "Discover total period",
            "series": [
                [1616168400, [{"count": 0}]],
                [1616168700, [{"count": 12}]],
                [1616169000, [{"count": 13}]],
            ],
        }

        service_url = "http://chartcuterie"
        image_data = b"this is png data"

        responses.add(
            method=responses.POST,
            url=f"{service_url}/render",
            status=200,
            content_type="image/png",
            body=image_data,
        )

        options = {
            "chart-rendering.enabled": True,
            "chart-rendering.chartcuterie": {"url": service_url},
        }

        # Don't upload our image anywhere
        with self.options(options):
            data = generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD, chart_data, upload=False)

        assert data == image_data

        request = responses.calls[0].request
        payload = json.loads(request.body)
        assert payload == {
            "requestId": "abc123",
            "style": ChartType.SLACK_DISCOVER_TOTAL_PERIOD.value,
            "data": chart_data,
        }

        # Test the image can be uploaded and we get a URL back
        with self.options(options):
            url = generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD, chart_data)

        assert url == absolute_uri(reverse("sentry-serve-media", args=["abc123.png"]))

        resp = self.client.get(url)
        assert next(resp.streaming_content) == image_data
Ejemplo n.º 3
0
    def test_failed(self):
        chart_data = {"seriesName": "Discover total period", "series": []}

        service_url = "http://chartcuterie"

        responses.add(
            method=responses.POST, url=f"{service_url}/render", status=500, body="Service down"
        )

        options = {
            "chart-rendering.enabled": True,
            "chart-rendering.chartcuterie": {"url": service_url},
        }

        with self.options(options), pytest.raises(
            RuntimeError, match="Chartcuterie responded with 500: Service down"
        ):
            generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD, chart_data)
    def get(self, request):
        charts = []

        url = generate_chart(ChartType.SLACK_DISCOVER_TOTAL_PERIOD,
                             discover_total)
        charts.append(url)

        return render_to_response("sentry/debug/chart-renderer.html",
                                  context={"charts": charts})
Ejemplo n.º 5
0
def unfurl_discover(data, integration,
                    links: List[UnfurlableUrl]) -> UnfurledUrl:
    orgs_by_slug = {org.slug: org for org in integration.organizations.all()}
    unfurls = {}

    for link in links:
        org_slug = link.args["org_slug"]
        org = orgs_by_slug.get(org_slug)

        # If the link shared is an org w/o the slack integration do not unfurl
        if not org:
            continue
        if not features.has("organizations:chart-unfurls", org):
            continue

        params = link.args["query"]
        query_id = params.get("id", None)

        saved_query = {}
        if query_id:
            try:
                response = client.get(
                    auth=ApiKey(organization=org, scope_list=["org:read"]),
                    path=
                    f"/organizations/{org_slug}/discover/saved/{query_id}/",
                )

            except Exception as exc:
                logger.error(
                    "Failed to load saved query for unfurl: %s",
                    str(exc),
                    exc_info=True,
                )
            else:
                saved_query = response.data

        # Override params from Discover Saved Query if they aren't in the URL
        params.setlist(
            "order",
            params.getlist("sort") or to_list(saved_query.get("orderby")))
        params.setlist(
            "name",
            params.getlist("name") or to_list(saved_query.get("name")))
        params.setlist(
            "yAxis",
            params.getlist("yAxis")
            or to_list(saved_query.get("yAxis", "count()")))
        params.setlist(
            "field",
            params.getlist("field") or to_list(saved_query.get("fields")))

        # Only override if key doesn't exist since we want to account for
        # an intermediate state where the query could have been cleared
        if "query" not in params:
            params.setlist(
                "query",
                params.getlist("query") or to_list(saved_query.get("query")))

        display_mode = str(
            params.get("display") or saved_query.get("display", "default"))

        if "daily" in display_mode:
            params.setlist("interval", ["1d"])
        if "top5" in display_mode:
            params.setlist("topEvents", [f"{TOP_N}"])

        try:
            resp = client.get(
                auth=ApiKey(organization=org, scope_list=["org:read"]),
                path=f"/organizations/{org_slug}/events-stats/",
                params=params,
            )
        except Exception as exc:
            logger.error(
                "Failed to load events-stats for unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        chart_data = {"seriesName": params.get("yAxis"), "stats": resp.data}

        style = display_modes.get(display_mode, display_modes["default"])

        try:
            url = generate_chart(style, chart_data)
        except RuntimeError as exc:
            logger.error(
                "Failed to generate chat for discover unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        unfurls[link.url] = build_discover_attachment(
            title=link.args["query"].get("name", "Dashboards query"),
            chart_url=url,
        )

    return unfurls
Ejemplo n.º 6
0
def unfurl_discover(data, integration,
                    links: List[UnfurlableUrl]) -> UnfurledUrl:
    orgs_by_slug = {org.slug: org for org in integration.organizations.all()}
    unfurls = {}

    for link in links:
        org_slug = link.args["org_slug"]
        org = orgs_by_slug.get(org_slug)

        # If the link shared is an org w/o the slack integration do not unfurl
        if not org:
            continue
        if not features.has("organizations:chart-unfurls", org):
            continue

        params = link.args["query"]
        params.setlist("order", params.get("sort"))
        display_mode = str(link.args["query"].get("display", "default"))

        if "daily" in display_mode:
            params.setlist("interval", ["1d"])
        if "top5" in display_mode:
            params.setlist("topEvents", [f"{TOP_N}"])

        try:
            resp = client.get(
                auth=ApiKey(organization=org, scope_list=["org:read"]),
                path=f"/organizations/{org_slug}/events-stats/",
                params=params,
            )
        except Exception as exc:
            logger.error(
                "Failed to load events-stats for unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        chart_data = {
            "seriesName": link.args["query"].get("yAxis", "count()"),
            "stats": resp.data
        }

        style = display_modes.get(display_mode, display_modes["default"])

        try:
            url = generate_chart(style, chart_data)
        except RuntimeError as exc:
            logger.error(
                "Failed to generate chat for discover unfurl: %s",
                str(exc),
                exc_info=True,
            )
            continue

        unfurls[link.url] = build_discover_attachment(
            title=link.args["query"].get("name", "Dashboards query"),
            chart_url=url,
        )

    return unfurls
Ejemplo n.º 7
0
def unfurl_discover(
    data: HttpRequest,
    integration: Integration,
    links: List[UnfurlableUrl],
    user: Optional["User"],
) -> UnfurledUrl:
    orgs_by_slug = {org.slug: org for org in integration.organizations.all()}
    unfurls = {}

    for link in links:
        org_slug = link.args["org_slug"]
        org = orgs_by_slug.get(org_slug)

        # If the link shared is an org w/o the slack integration do not unfurl
        if not org:
            continue
        if not features.has("organizations:discover-basic", org):
            continue

        params = link.args["query"]
        query_id = params.get("id", None)

        saved_query = {}
        if query_id:
            try:
                response = client.get(
                    auth=ApiKey(organization=org, scope_list=["org:read"]),
                    path=f"/organizations/{org_slug}/discover/saved/{query_id}/",
                )

            except Exception as exc:
                logger.error(
                    f"Failed to load saved query for unfurl: {exc}",
                    exc_info=True,
                )
            else:
                saved_query = response.data

        # Override params from Discover Saved Query if they aren't in the URL
        params.setlist(
            "order",
            params.getlist("sort")
            or (to_list(saved_query.get("orderby")) if saved_query.get("orderby") else []),
        )
        params.setlist("name", params.getlist("name") or to_list(saved_query.get("name")))

        fields = params.getlist("field") or to_list(saved_query.get("fields"))
        # Mimic Discover to pick the first aggregate as the yAxis option if
        # one isn't specified.
        axis_options = [field for field in fields if is_aggregate(field)] + [DEFAULT_AXIS_OPTION]
        params.setlist(
            "yAxis", params.getlist("yAxis") or to_list(saved_query.get("yAxis", axis_options[0]))
        )
        params.setlist("field", params.getlist("field") or to_list(saved_query.get("fields")))

        params.setlist(
            "project",
            params.getlist("project")
            or (to_list(saved_query.get("project")) if saved_query.get("project") else []),
        )

        # Only override if key doesn't exist since we want to account for
        # an intermediate state where the query could have been cleared
        if "query" not in params:
            params.setlist(
                "query", params.getlist("query") or to_list(saved_query.get("query", ""))
            )

        display_mode = str(params.get("display") or saved_query.get("display", "default"))

        if "daily" in display_mode:
            params.setlist("interval", ["1d"])

        if "top5" in display_mode:
            params.setlist(
                "topEvents",
                params.getlist("topEvents") or to_list(saved_query.get("topEvents", f"{TOP_N}")),
            )

            y_axis = params.getlist("yAxis")[0]
            if display_mode != "dailytop5":
                display_mode = get_top5_display_mode(y_axis)

        else:
            # topEvents param persists in the URL in some cases, we want to discard
            # it if it's not a top n display type.
            params.pop("topEvents", None)

        if "previous" in display_mode:
            stats_period = params.getlist("statsPeriod", [DEFAULT_PERIOD])[0]
            parsed_period = parse_stats_period(stats_period)
            if parsed_period and parsed_period <= timedelta(days=MAX_PERIOD_DAYS_INCLUDE_PREVIOUS):
                stats_period = get_double_period(stats_period)
                params.setlist("statsPeriod", [stats_period])

        endpoint = "events-stats/"
        if "worldmap" in display_mode:
            endpoint = "events-geo/"
            params.setlist("field", params.getlist("yAxis"))
            params.pop("sort", None)

        try:
            resp = client.get(
                auth=ApiKey(organization=org, scope_list=["org:read"]),
                user=user,
                path=f"/organizations/{org_slug}/{endpoint}",
                params=params,
            )
        except Exception as exc:
            logger.error(
                f"Failed to load {endpoint} for unfurl: {exc}",
                exc_info=True,
            )
            continue

        chart_data = {"seriesName": params.get("yAxis"), "stats": resp.data}

        style = display_modes.get(display_mode, display_modes["default"])

        try:
            url = generate_chart(style, chart_data)
        except RuntimeError as exc:
            logger.error(
                f"Failed to generate chart for discover unfurl: {exc}",
                exc_info=True,
            )
            continue

        unfurls[link.url] = SlackDiscoverMessageBuilder(
            title=link.args["query"].get("name", "Dashboards query"),
            chart_url=url,
        ).build()

    analytics.record(
        "integrations.slack.chart_unfurl",
        organization_id=integration.organizations.all()[0].id,
        user_id=user.id if user else None,
        unfurls_count=len(unfurls),
    )

    return unfurls