mirror of https://github.com/zulip/zulip.git
sentry: Untangle from page_params.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
3db05666ac
commit
f7eecb0e03
|
@ -23,6 +23,10 @@
|
|||
{% include 'zerver/meta_tags.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% if sentry_params is defined %}
|
||||
<script id="sentry-params" type="text/json">{{ sentry_params|tojson }}</script>
|
||||
{% endif %}
|
||||
|
||||
{% block webpack %}
|
||||
{% for filename in webpack_entry(entrypoint) -%}
|
||||
{% if filename.endswith(".css") -%}
|
||||
|
|
|
@ -10,12 +10,7 @@ const default_params_schema = z.object({
|
|||
page_type: z.literal("default"),
|
||||
development_environment: z.boolean(),
|
||||
google_analytics_id: z.optional(z.string()),
|
||||
realm_sentry_key: z.optional(z.string()),
|
||||
request_language: z.string(),
|
||||
server_sentry_dsn: z.nullable(z.string()),
|
||||
server_sentry_environment: z.optional(z.string()),
|
||||
server_sentry_sample_rate: z.optional(z.number()),
|
||||
server_sentry_trace_rate: z.optional(z.number()),
|
||||
});
|
||||
|
||||
// These parameters are sent in #page-params for both users and spectators.
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
import * as Sentry from "@sentry/browser";
|
||||
import assert from "minimalistic-assert";
|
||||
|
||||
import {page_params} from "./base_page_params";
|
||||
import {current_user, realm} from "./state_data";
|
||||
import {z} from "zod";
|
||||
|
||||
type UserInfo = {
|
||||
id?: string;
|
||||
|
@ -10,13 +7,22 @@ type UserInfo = {
|
|||
role?: string;
|
||||
};
|
||||
|
||||
const sentry_key =
|
||||
// No parameter is the portico pages, empty string is the empty realm
|
||||
page_params.realm_sentry_key === undefined
|
||||
? "www"
|
||||
: page_params.realm_sentry_key === ""
|
||||
? "(root)"
|
||||
: page_params.realm_sentry_key;
|
||||
const sentry_params_schema = z.object({
|
||||
dsn: z.string(),
|
||||
environment: z.string(),
|
||||
realm_key: z.string(),
|
||||
sample_rate: z.number(),
|
||||
server_version: z.string(),
|
||||
trace_rate: z.number(),
|
||||
user: z.object({id: z.number(), role: z.string()}).optional(),
|
||||
});
|
||||
|
||||
const sentry_params_json =
|
||||
window.document?.querySelector("script#sentry-params")?.textContent ?? undefined;
|
||||
const sentry_params =
|
||||
sentry_params_json === undefined
|
||||
? undefined
|
||||
: sentry_params_schema.parse(JSON.parse(sentry_params_json));
|
||||
|
||||
export function normalize_path(path: string, is_portico = false): string {
|
||||
if (path === undefined) {
|
||||
|
@ -39,36 +45,7 @@ export function shouldCreateSpanForRequest(url: string): boolean {
|
|||
return parsed.pathname !== "/json/events";
|
||||
}
|
||||
|
||||
export function initialize(): void {
|
||||
// The current_user and realm structures are not available until this is
|
||||
// called from ui_init.initialize_everything.
|
||||
assert(page_params.page_type === "home");
|
||||
|
||||
const user_role = current_user.is_owner
|
||||
? "Organization owner"
|
||||
: current_user.is_admin
|
||||
? "Organization administrator"
|
||||
: current_user.is_moderator
|
||||
? "Moderator"
|
||||
: current_user.is_guest
|
||||
? "Guest"
|
||||
: page_params.is_spectator
|
||||
? "Spectator"
|
||||
: current_user.user_id
|
||||
? "Member"
|
||||
: "Logged out";
|
||||
const user_info: UserInfo = {realm: sentry_key, role: user_role};
|
||||
if (current_user.user_id) {
|
||||
user_info.id = current_user.user_id.toString();
|
||||
}
|
||||
Sentry.setTags({
|
||||
user_role,
|
||||
server_version: realm.zulip_version,
|
||||
});
|
||||
Sentry.setUser(user_info);
|
||||
}
|
||||
|
||||
if (page_params.server_sentry_dsn) {
|
||||
if (sentry_params !== undefined) {
|
||||
const sample_rates = new Map([
|
||||
// This is controlled by shouldCreateSpanForRequest, above, but also put here for consistency
|
||||
["call GET /json/events", 0],
|
||||
|
@ -78,8 +55,8 @@ if (page_params.server_sentry_dsn) {
|
|||
]);
|
||||
|
||||
Sentry.init({
|
||||
dsn: page_params.server_sentry_dsn,
|
||||
environment: page_params.server_sentry_environment ?? "development",
|
||||
dsn: sentry_params.dsn,
|
||||
environment: sentry_params.environment,
|
||||
tunnel: "/error_tracing",
|
||||
|
||||
release: "zulip-server@" + ZULIP_VERSION,
|
||||
|
@ -90,25 +67,34 @@ if (page_params.server_sentry_dsn) {
|
|||
return {
|
||||
...context,
|
||||
metadata: {source: "custom"},
|
||||
name: normalize_path(window.location.pathname, sentry_key === "www"),
|
||||
name: normalize_path(
|
||||
window.location.pathname,
|
||||
sentry_params.realm_key === "www",
|
||||
),
|
||||
};
|
||||
},
|
||||
shouldCreateSpanForRequest,
|
||||
}),
|
||||
],
|
||||
sampleRate: page_params.server_sentry_sample_rate ?? 0,
|
||||
sampleRate: sentry_params.sample_rate,
|
||||
tracesSampler(samplingContext) {
|
||||
const base_rate = page_params.server_sentry_trace_rate ?? 0;
|
||||
const base_rate = sentry_params.trace_rate;
|
||||
const name = samplingContext.transactionContext.name;
|
||||
return base_rate * (sample_rates.get(name) ?? 1);
|
||||
},
|
||||
initialScope(scope) {
|
||||
const user_role = sentry_params.user?.role ?? "Logged out";
|
||||
const user_info: UserInfo = {
|
||||
realm: sentry_key,
|
||||
realm: sentry_params.realm_key,
|
||||
role: user_role,
|
||||
};
|
||||
if (sentry_params.user !== undefined) {
|
||||
user_info.id = sentry_params.user.id.toString();
|
||||
}
|
||||
scope.setTags({
|
||||
realm: sentry_key,
|
||||
user_role: "Browser",
|
||||
realm: sentry_params.realm_key,
|
||||
server_version: sentry_params.server_version,
|
||||
user_role,
|
||||
});
|
||||
scope.setUser(user_info);
|
||||
return scope;
|
||||
|
|
|
@ -103,7 +103,6 @@ import * as scheduled_messages_ui from "./scheduled_messages_ui";
|
|||
import * as scroll_bar from "./scroll_bar";
|
||||
import * as scroll_util from "./scroll_util";
|
||||
import * as search from "./search";
|
||||
import * as sentry from "./sentry";
|
||||
import * as server_events from "./server_events";
|
||||
import * as settings from "./settings";
|
||||
import * as settings_data from "./settings_data";
|
||||
|
@ -414,7 +413,6 @@ export function initialize_everything(state_data) {
|
|||
|
||||
set_current_user(state_data.current_user);
|
||||
set_realm(state_data.realm);
|
||||
sentry.initialize();
|
||||
|
||||
/* To store theme data for spectators, we need to initialize
|
||||
user_settings before setting the theme. Because information
|
||||
|
|
|
@ -6,6 +6,7 @@ from django.http import HttpRequest
|
|||
from django.utils.html import escape
|
||||
from django.utils.safestring import SafeString
|
||||
from django.utils.translation import get_language
|
||||
from django.utils.translation import override as override_language
|
||||
|
||||
from version import (
|
||||
LATEST_MAJOR_VERSION,
|
||||
|
@ -168,17 +169,8 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
|
|||
# Sync this with default_params_schema in base_page_params.ts.
|
||||
default_page_params: Dict[str, Any] = {
|
||||
**DEFAULT_PAGE_PARAMS,
|
||||
"server_sentry_dsn": settings.SENTRY_FRONTEND_DSN,
|
||||
"request_language": get_language(),
|
||||
}
|
||||
if settings.SENTRY_FRONTEND_DSN is not None:
|
||||
if realm is not None:
|
||||
default_page_params["realm_sentry_key"] = realm.string_id
|
||||
default_page_params["server_sentry_environment"] = get_config(
|
||||
"machine", "deploy_type", "development"
|
||||
)
|
||||
default_page_params["server_sentry_sample_rate"] = settings.SENTRY_FRONTEND_SAMPLE_RATE
|
||||
default_page_params["server_sentry_trace_rate"] = settings.SENTRY_FRONTEND_TRACE_RATE
|
||||
|
||||
context = {
|
||||
"root_domain_landing_page": settings.ROOT_DOMAIN_LANDING_PAGE,
|
||||
|
@ -217,6 +209,23 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]:
|
|||
"corporate_enabled": corporate_enabled,
|
||||
}
|
||||
|
||||
if settings.SENTRY_FRONTEND_DSN is not None:
|
||||
sentry_params = {
|
||||
"dsn": settings.SENTRY_FRONTEND_DSN,
|
||||
"environment": get_config("machine", "deploy_type", "development"),
|
||||
"realm_key": "www" if realm is None else realm.string_id or "(root)",
|
||||
"sample_rate": settings.SENTRY_FRONTEND_SAMPLE_RATE,
|
||||
"server_version": ZULIP_VERSION,
|
||||
"trace_rate": settings.SENTRY_FRONTEND_TRACE_RATE,
|
||||
}
|
||||
if request.user.is_authenticated:
|
||||
with override_language(None):
|
||||
sentry_params["user"] = {
|
||||
"id": request.user.id,
|
||||
"role": request.user.get_role_name(),
|
||||
}
|
||||
context["sentry_params"] = sentry_params
|
||||
|
||||
context["PAGE_METADATA_URL"] = f"{realm_url}{request.path}"
|
||||
if realm is not None and realm.icon_source == realm.ICON_UPLOADED:
|
||||
context["PAGE_METADATA_IMAGE"] = urljoin(realm_url, realm_icon)
|
||||
|
|
|
@ -20,7 +20,6 @@ from zerver.lib.realm_description import get_realm_rendered_description
|
|||
from zerver.lib.request import RequestNotes
|
||||
from zerver.models import Message, Realm, Stream, UserProfile
|
||||
from zerver.views.message_flags import get_latest_update_message_flag_activity
|
||||
from zproject.config import get_config
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -230,17 +229,8 @@ def build_page_params_for_home_page_load(
|
|||
# There is no event queue for spectators since
|
||||
# events support for spectators is not implemented yet.
|
||||
no_event_queue=user_profile is None,
|
||||
server_sentry_dsn=settings.SENTRY_FRONTEND_DSN,
|
||||
)
|
||||
|
||||
if settings.SENTRY_FRONTEND_DSN is not None:
|
||||
page_params["realm_sentry_key"] = realm.string_id
|
||||
page_params["server_sentry_environment"] = get_config(
|
||||
"machine", "deploy_type", "development"
|
||||
)
|
||||
page_params["server_sentry_sample_rate"] = settings.SENTRY_FRONTEND_SAMPLE_RATE
|
||||
page_params["server_sentry_trace_rate"] = settings.SENTRY_FRONTEND_TRACE_RATE
|
||||
|
||||
page_params["state_data"] = state_data
|
||||
|
||||
if narrow_stream is not None and state_data is not None:
|
||||
|
|
|
@ -699,6 +699,15 @@ Output:
|
|||
page_params = orjson.loads(page_params_json)
|
||||
return page_params
|
||||
|
||||
def _get_sentry_params(self, response: "TestHttpResponse") -> Optional[Dict[str, Any]]:
|
||||
doc = lxml.html.document_fromstring(response.content)
|
||||
try:
|
||||
script = cast(lxml.html.HtmlMixin, doc).get_element_by_id("sentry-params")
|
||||
except KeyError:
|
||||
return None
|
||||
assert script is not None and script.text is not None
|
||||
return orjson.loads(script.text)
|
||||
|
||||
def check_rendered_logged_in_app(self, result: "TestHttpResponse") -> None:
|
||||
"""Verifies that a visit of / was a 200 that rendered page_params
|
||||
and not for a (logged-out) spectator."""
|
||||
|
|
|
@ -11,6 +11,7 @@ from django.test import override_settings
|
|||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from corporate.models import Customer, CustomerPlan
|
||||
from version import ZULIP_VERSION
|
||||
from zerver.actions.create_user import do_create_user
|
||||
from zerver.actions.realm_settings import do_change_realm_plan_type, do_set_realm_property
|
||||
from zerver.actions.users import change_user_is_active
|
||||
|
@ -55,7 +56,6 @@ class HomeTest(ZulipTestCase):
|
|||
"page_type",
|
||||
"promote_sponsoring_zulip",
|
||||
"request_language",
|
||||
"server_sentry_dsn",
|
||||
"show_billing",
|
||||
"show_plans",
|
||||
"show_remote_billing",
|
||||
|
@ -358,7 +358,6 @@ class HomeTest(ZulipTestCase):
|
|||
"promote_sponsoring_zulip",
|
||||
"realm_rendered_description",
|
||||
"request_language",
|
||||
"server_sentry_dsn",
|
||||
"show_billing",
|
||||
"show_plans",
|
||||
"show_remote_billing",
|
||||
|
@ -497,47 +496,47 @@ class HomeTest(ZulipTestCase):
|
|||
)
|
||||
|
||||
def test_sentry_keys(self) -> None:
|
||||
def home_params() -> Dict[str, Any]:
|
||||
def sentry_params() -> Dict[str, Any] | None:
|
||||
result = self._get_home_page()
|
||||
self.assertEqual(result.status_code, 200)
|
||||
return self._get_page_params(result)
|
||||
return self._get_sentry_params(result)
|
||||
|
||||
self.login("hamlet")
|
||||
page_params = home_params()
|
||||
self.assertEqual(page_params["server_sentry_dsn"], None)
|
||||
self.assertEqual(
|
||||
[], [key for key in page_params if key != "server_sentry_dsn" and "sentry" in key]
|
||||
)
|
||||
user = self.example_user("hamlet")
|
||||
self.login_user(user)
|
||||
self.assertIsNone(sentry_params())
|
||||
|
||||
with self.settings(SENTRY_FRONTEND_DSN="https://aaa@bbb.ingest.sentry.io/1234"):
|
||||
page_params = home_params()
|
||||
self.assertEqual(
|
||||
page_params["server_sentry_dsn"], "https://aaa@bbb.ingest.sentry.io/1234"
|
||||
sentry_params(),
|
||||
{
|
||||
"dsn": "https://aaa@bbb.ingest.sentry.io/1234",
|
||||
"environment": "development",
|
||||
"realm_key": "zulip",
|
||||
"sample_rate": 1.0,
|
||||
"server_version": ZULIP_VERSION,
|
||||
"trace_rate": 0.1,
|
||||
"user": {"id": user.id, "role": "Member"},
|
||||
},
|
||||
)
|
||||
self.assertEqual(page_params["realm_sentry_key"], "zulip")
|
||||
self.assertEqual(page_params["server_sentry_environment"], "development")
|
||||
self.assertEqual(page_params["server_sentry_sample_rate"], 1.0)
|
||||
self.assertEqual(page_params["server_sentry_trace_rate"], 0.1)
|
||||
|
||||
# Make sure these still exist for logged-out users as well
|
||||
realm = get_realm("zulip")
|
||||
do_set_realm_property(realm, "enable_spectator_access", True, acting_user=None)
|
||||
self.logout()
|
||||
page_params = home_params()
|
||||
self.assertEqual(page_params["server_sentry_dsn"], None)
|
||||
self.assertEqual(
|
||||
[], [key for key in page_params if key != "server_sentry_dsn" and "sentry" in key]
|
||||
)
|
||||
self.assertIsNone(sentry_params())
|
||||
|
||||
with self.settings(SENTRY_FRONTEND_DSN="https://aaa@bbb.ingest.sentry.io/1234"):
|
||||
page_params = home_params()
|
||||
self.assertEqual(
|
||||
page_params["server_sentry_dsn"], "https://aaa@bbb.ingest.sentry.io/1234"
|
||||
sentry_params(),
|
||||
{
|
||||
"dsn": "https://aaa@bbb.ingest.sentry.io/1234",
|
||||
"environment": "development",
|
||||
"realm_key": "zulip",
|
||||
"sample_rate": 1.0,
|
||||
"server_version": ZULIP_VERSION,
|
||||
"trace_rate": 0.1,
|
||||
},
|
||||
)
|
||||
self.assertEqual(page_params["realm_sentry_key"], "zulip")
|
||||
self.assertEqual(page_params["server_sentry_environment"], "development")
|
||||
self.assertEqual(page_params["server_sentry_sample_rate"], 1.0)
|
||||
self.assertEqual(page_params["server_sentry_trace_rate"], 0.1)
|
||||
|
||||
def test_home_under_2fa_without_otp_device(self) -> None:
|
||||
with self.settings(TWO_FACTOR_AUTHENTICATION_ENABLED=True):
|
||||
|
|
Loading…
Reference in New Issue