diff --git a/static/app/gettingStartedDocs/python/aiohttp.tsx b/static/app/gettingStartedDocs/python/aiohttp.tsx index 27c5ff06df7cf3..6ce6aebb786e4f 100644 --- a/static/app/gettingStartedDocs/python/aiohttp.tsx +++ b/static/app/gettingStartedDocs/python/aiohttp.tsx @@ -9,21 +9,20 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; -import {t, tct} from 'sentry/locale'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; import { - alternativeProfilingConfiguration, getPythonAiocontextvarsCodeBlocks, getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; +} from 'sentry/gettingStartedDocs/python/python/utils'; +import {t, tct} from 'sentry/locale'; type Params = DocsParams; @@ -112,7 +111,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -140,7 +139,7 @@ app.add_routes([web.get('/', hello)]) web.run_app(app) `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -175,18 +174,16 @@ web.run_app(app) }, }; -const logsOnboarding = getPythonLogsOnboarding(); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding(), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + profilingOnboarding: profiling(), + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/asgi.tsx b/static/app/gettingStartedDocs/python/asgi.tsx index 26a893ae4539c5..603b0cc7492cd8 100644 --- a/static/app/gettingStartedDocs/python/asgi.tsx +++ b/static/app/gettingStartedDocs/python/asgi.tsx @@ -5,19 +5,16 @@ import { type DocsParams, type OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -130,7 +127,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), { type: 'text', text: t('The middleware supports both ASGI 2 and ASGI 3 transparently.'), @@ -151,7 +148,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getVerifySnippet(), }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: tct( @@ -187,15 +184,13 @@ const onboarding: OnboardingConfig = { }, }; -const logsOnboarding = getPythonLogsOnboarding(); - const docs: Docs = { onboarding, - crashReportOnboarding: crashReportOnboardingPython, - profilingOnboarding: getPythonProfilingOnboarding(), - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + crashReportOnboarding: crashReport, + profilingOnboarding: profiling(), + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/awslambda.tsx b/static/app/gettingStartedDocs/python/awslambda.tsx index 48c7d2c9b90610..e9038013372be0 100644 --- a/static/app/gettingStartedDocs/python/awslambda.tsx +++ b/static/app/gettingStartedDocs/python/awslambda.tsx @@ -6,17 +6,12 @@ import { type OnboardingConfig, type OnboardingStep, } from 'sentry/components/onboarding/gettingStartedDoc/types'; -import { - agentMonitoringOnboarding, - crashReportOnboardingPython, -} from 'sentry/gettingStartedDocs/python/python'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {alternativeProfiling} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -99,7 +94,7 @@ const configureStep = (params: Params): OnboardingStep => ({ language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), { type: 'text', text: tct("Check out Sentry's [link:AWS sample apps] for detailed examples.", { @@ -181,7 +176,7 @@ const onboarding: OnboardingConfig = { 'Deploy your function and invoke it to generate an error, then check Sentry for the captured event.' ), }, - getVerifyLogsContent(params), + verify(params), ], }, ], @@ -219,14 +214,12 @@ const profilingOnboarding: OnboardingConfig = { ], }; -const logsOnboarding = getPythonLogsOnboarding(); - const docs: Docs = { onboarding, - crashReportOnboarding: crashReportOnboardingPython, + crashReportOnboarding: crashReport, profilingOnboarding, - agentMonitoringOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/bottle.tsx b/static/app/gettingStartedDocs/python/bottle.tsx index 7be67160a51618..465f0fd1167244 100644 --- a/static/app/gettingStartedDocs/python/bottle.tsx +++ b/static/app/gettingStartedDocs/python/bottle.tsx @@ -9,20 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -108,7 +105,7 @@ ${getSdkSetupSnippet(params)} app = Bottle() `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -135,7 +132,7 @@ def hello(): run(app, host='localhost', port=8000) `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -170,20 +167,18 @@ run(app, host='localhost', port=8000) }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[bottle]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[bottle]'}), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[bottle]'}), + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[bottle]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/celery.tsx b/static/app/gettingStartedDocs/python/celery.tsx index 961370327700b8..b3cd1af7a5cc48 100644 --- a/static/app/gettingStartedDocs/python/celery.tsx +++ b/static/app/gettingStartedDocs/python/celery.tsx @@ -5,18 +5,15 @@ import { type DocsParams, type OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -107,7 +104,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), { type: 'subheader', text: t('Standalone Setup'), @@ -200,22 +197,20 @@ def hello(): hello.delay() `, }, - getVerifyLogsContent(params), + verify(params), ], }, ], }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[celery]', -}); - const docs: Docs = { onboarding, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[celery]'}), - crashReportOnboarding: crashReportOnboardingPython, - agentMonitoringOnboarding, - logsOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[celery]'}), + crashReportOnboarding: crashReport, + agentMonitoringOnboarding: agentMonitoring, + logsOnboarding: logs({ + packageName: 'sentry-sdk[celery]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/chalice.tsx b/static/app/gettingStartedDocs/python/chalice.tsx index 7122a2058fa4cb..ff3f617d191538 100644 --- a/static/app/gettingStartedDocs/python/chalice.tsx +++ b/static/app/gettingStartedDocs/python/chalice.tsx @@ -4,19 +4,16 @@ import { type DocsParams, type OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -110,7 +107,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -127,7 +124,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getVerifySnippet(), }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: tct( @@ -142,17 +139,15 @@ const onboarding: OnboardingConfig = { ], }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[chalice]', -}); - const docs: Docs = { onboarding, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[chalice]'}), - crashReportOnboarding: crashReportOnboardingPython, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[chalice]'}), + crashReportOnboarding: crashReport, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[chalice]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/django.tsx b/static/app/gettingStartedDocs/python/django.tsx index 52b14ba2313ad7..5426f1ee7a2839 100644 --- a/static/app/gettingStartedDocs/python/django.tsx +++ b/static/app/gettingStartedDocs/python/django.tsx @@ -9,20 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -103,7 +100,7 @@ const onboarding: OnboardingConfig = { }, ], }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -137,7 +134,7 @@ urlpatterns = [ }, ], }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -243,22 +240,19 @@ sentry_sdk.init( nextSteps: () => [], }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[django]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[django]'}), + profilingOnboarding: profiling({basePackage: 'sentry-sdk[django]'}), performanceOnboarding, - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[django]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/falcon.tsx b/static/app/gettingStartedDocs/python/falcon.tsx index 1dbe6386aab14a..9ee893d54f0c85 100644 --- a/static/app/gettingStartedDocs/python/falcon.tsx +++ b/static/app/gettingStartedDocs/python/falcon.tsx @@ -9,20 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -109,7 +106,7 @@ ${getSdkSetupSnippet(params)} api = falcon.API() `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -138,7 +135,7 @@ app = falcon.App() app.add_route('/', HelloWorldResource()) `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -173,20 +170,18 @@ app.add_route('/', HelloWorldResource()) }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[falcon]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[falcon]'}), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[falcon]'}), + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[falcon]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/fastapi.tsx b/static/app/gettingStartedDocs/python/fastapi.tsx index 3054126c4a25c8..f2e36f0e5f4b0c 100644 --- a/static/app/gettingStartedDocs/python/fastapi.tsx +++ b/static/app/gettingStartedDocs/python/fastapi.tsx @@ -9,20 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -112,7 +109,7 @@ ${getSdkSetupSnippet(params)} app = FastAPI() `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), { type: 'text', text: tct( @@ -144,7 +141,7 @@ async def trigger_error(): division_by_zero = 1 / 0 `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -179,20 +176,18 @@ async def trigger_error(): }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[fastapi]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[fastapi]'}), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[fastapi]'}), + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[fastapi]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/flask.tsx b/static/app/gettingStartedDocs/python/flask.tsx index 17e41d8d617911..39b4a0f25c1421 100644 --- a/static/app/gettingStartedDocs/python/flask.tsx +++ b/static/app/gettingStartedDocs/python/flask.tsx @@ -9,20 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -107,7 +104,7 @@ const onboarding: OnboardingConfig = { app = Flask(__name__) `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), { type: 'text', text: tct( @@ -140,7 +137,7 @@ def hello_world(): return "

Hello, World!

" `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -246,21 +243,19 @@ sentry_sdk.init( nextSteps: () => [], }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[flask]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[flask]'}), + profilingOnboarding: profiling({basePackage: 'sentry-sdk[flask]'}), performanceOnboarding, - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[flask]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/gcpfunctions.tsx b/static/app/gettingStartedDocs/python/gcpfunctions.tsx index 82bfe8be221065..46a08a281ae527 100644 --- a/static/app/gettingStartedDocs/python/gcpfunctions.tsx +++ b/static/app/gettingStartedDocs/python/gcpfunctions.tsx @@ -5,19 +5,16 @@ import { type DocsParams, type OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -105,7 +102,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), { type: 'text', text: tct("Check out Sentry's [link:GCP sample apps] for detailed examples.", { @@ -173,7 +170,7 @@ const onboarding: OnboardingConfig = { 'Deploy your function and invoke it to generate an error, then check Sentry for the captured event.' ), }, - getVerifyLogsContent(params), + verify(params), ], }, ], @@ -193,15 +190,13 @@ const onboarding: OnboardingConfig = { }, }; -const logsOnboarding = getPythonLogsOnboarding(); - const docs: Docs = { onboarding, - crashReportOnboarding: crashReportOnboardingPython, - profilingOnboarding: getPythonProfilingOnboarding(), - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + crashReportOnboarding: crashReport, + profilingOnboarding: profiling(), + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/pyramid.tsx b/static/app/gettingStartedDocs/python/pyramid.tsx index 5f1559027d66bf..851531f556c43a 100644 --- a/static/app/gettingStartedDocs/python/pyramid.tsx +++ b/static/app/gettingStartedDocs/python/pyramid.tsx @@ -9,18 +9,13 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; -import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {profiling} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -115,7 +110,7 @@ if __name__ == '__main__': server.serve_forever() `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: tct( @@ -144,17 +139,15 @@ if __name__ == '__main__': }, }; -const logsOnboarding = getPythonLogsOnboarding(); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding(), - agentMonitoringOnboarding, - logsOnboarding, + profilingOnboarding: profiling(), + agentMonitoringOnboarding: agentMonitoring, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/python.tsx b/static/app/gettingStartedDocs/python/python/agentMonitoring.tsx similarity index 50% rename from static/app/gettingStartedDocs/python/python.tsx rename to static/app/gettingStartedDocs/python/python/agentMonitoring.tsx index 5aaca8df2f948e..578ea79885f276 100644 --- a/static/app/gettingStartedDocs/python/python.tsx +++ b/static/app/gettingStartedDocs/python/python/agentMonitoring.tsx @@ -1,676 +1,15 @@ import {ExternalLink} from 'sentry/components/core/link'; -import {SdkProviderEnum as FeatureFlagProviderEnum} from 'sentry/components/events/featureFlags/utils'; -import { - StepType, - type Docs, - type DocsParams, - type OnboardingConfig, - type OnboardingStep, +import type { + OnboardingConfig, + OnboardingStep, } from 'sentry/components/onboarding/gettingStartedDoc/types'; -import { - getCrashReportBackendInstallSteps, - getCrashReportModalConfigDescription, - getCrashReportModalIntroduction, -} from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding'; +import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; -type Params = DocsParams; +import {getPythonInstallCodeBlock} from './utils'; -type FeatureFlagConfiguration = { - integrationName: string; - makeConfigureCode: (dsn: string) => string; - makeVerifyCode: () => string; - packageName: string; -}; - -const FEATURE_FLAG_CONFIGURATION_MAP: Record< - FeatureFlagProviderEnum, - FeatureFlagConfiguration -> = { - [FeatureFlagProviderEnum.GENERIC]: { - integrationName: ``, - packageName: 'sentry-sdk', - makeConfigureCode: (dsn: string) => `sentry_sdk.init( - dsn="${dsn}", - # Add data like request headers and IP for users, if applicable; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[ - # your other integrations here - ], -)`, - makeVerifyCode: () => `import sentry_sdk -from sentry_sdk.feature_flags import add_feature_flag - -add_feature_flag('test-flag', False) # Records an evaluation and its result. -sentry_sdk.capture_exception(Exception("Something went wrong!"))`, - }, - - [FeatureFlagProviderEnum.LAUNCHDARKLY]: { - integrationName: `LaunchDarklyIntegration`, - packageName: "'sentry-sdk[launchdarkly]'", - makeConfigureCode: (dsn: string) => `import sentry_sdk -from sentry_sdk.integrations.launchdarkly import LaunchDarklyIntegration -import ldclient - -sentry_sdk.init( - dsn="${dsn}", - # Add data like request headers and IP for users, if applicable; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[ - LaunchDarklyIntegration(), - ], -)`, - makeVerifyCode: () => `client = ldclient.get() -client.variation("hello", Context.create("test-context"), False) # Evaluate a flag with a default value. -sentry_sdk.capture_exception(Exception("Something went wrong!"))`, - }, - - [FeatureFlagProviderEnum.OPENFEATURE]: { - integrationName: `OpenFeatureIntegration`, - packageName: "'sentry-sdk[openfeature]'", - makeConfigureCode: (dsn: string) => `import sentry_sdk -from sentry_sdk.integrations.openfeature import OpenFeatureIntegration -from openfeature import api - -sentry_sdk.init( - dsn="${dsn}", - # Add data like request headers and IP for users, if applicable; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[ - OpenFeatureIntegration(), - ], -)`, - makeVerifyCode: () => `client = api.get_client() -client.get_boolean_value("hello", default_value=False) # Evaluate a flag with a default value. -sentry_sdk.capture_exception(Exception("Something went wrong!"))`, - }, - - [FeatureFlagProviderEnum.STATSIG]: { - integrationName: `StatsigIntegration`, - packageName: "'sentry-sdk[statsig]'", - makeConfigureCode: (dsn: string) => `import sentry_sdk -from sentry_sdk.integrations.statsig import StatsigIntegration -from statsig.statsig_user import StatsigUser -from statsig import statsig -import time - -sentry_sdk.init( - dsn="${dsn}", - # Add data like request headers and IP for users, if applicable; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[StatsigIntegration()], -) -statsig.initialize("server-secret-key")`, - makeVerifyCode: () => `while not statsig.is_initialized(): - time.sleep(0.2) - -result = statsig.check_gate(StatsigUser("my-user-id"), "my-feature-gate") # Evaluate a flag. -sentry_sdk.capture_exception(Exception("Something went wrong!"))`, - }, - - [FeatureFlagProviderEnum.UNLEASH]: { - integrationName: `UnleashIntegration`, - packageName: "'sentry-sdk[unleash]'", - makeConfigureCode: (dsn: string) => `import sentry_sdk -from sentry_sdk.integrations.unleash import UnleashIntegration -from UnleashClient import UnleashClient - -sentry_sdk.init( - dsn="${dsn}", - # Add data like request headers and IP for users, if applicable; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[UnleashIntegration()], -) - -unleash = UnleashClient(...) # See Unleash quickstart. -unleash.initialize_client()`, - makeVerifyCode: - () => `test_flag_enabled = unleash.is_enabled("test-flag") # Evaluate a flag. -sentry_sdk.capture_exception(Exception("Something went wrong!"))`, - }, -}; - -const getSdkSetupSnippet = (params: Params) => ` -import sentry_sdk - -sentry_sdk.init( - dsn="${params.dsn.public}", - # Add data like request headers and IP for users, - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True,${ - params.isLogsSelected - ? ` - # Enable sending logs to Sentry - enable_logs=True,` - : '' - }${ - params.isPerformanceSelected - ? ` - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for tracing. - traces_sample_rate=1.0,` - : '' - }${ - params.isProfilingSelected && - params.profilingOptions?.defaultProfilingMode !== 'continuous' - ? ` - # Set profiles_sample_rate to 1.0 to profile 100% - # of sampled transactions. - # We recommend adjusting this value in production. - profiles_sample_rate=1.0,` - : params.isProfilingSelected && - params.profilingOptions?.defaultProfilingMode === 'continuous' - ? ` - # Set profile_session_sample_rate to 1.0 to profile 100% - # of profile sessions. - profile_session_sample_rate=1.0,` - : '' - } -)${ - params.isProfilingSelected && - params.profilingOptions?.defaultProfilingMode === 'continuous' - ? ` - -def slow_function(): - import time - time.sleep(0.1) - return "done" - -def fast_function(): - import time - time.sleep(0.05) - return "done" - -# Manually call start_profiler and stop_profiler -# to profile the code in between -sentry_sdk.profiler.start_profiler() - -for i in range(0, 10): - slow_function() - fast_function() - -# Calls to stop_profiler are optional - if you don't stop the profiler, it will keep profiling -# your application until the process exits or stop_profiler is called. -sentry_sdk.profiler.stop_profiler()` - : '' -}`; - -const onboarding: OnboardingConfig = { - install: () => [ - { - type: StepType.INSTALL, - content: [ - { - type: 'text', - text: tct('Install our Python SDK:', { - code: , - }), - }, - getPythonInstallCodeBlock(), - ], - }, - ], - configure: (params: Params) => [ - { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: t( - "Import and initialize the Sentry SDK early in your application's setup:" - ), - }, - { - type: 'code', - language: 'python', - code: getSdkSetupSnippet(params), - }, - alternativeProfilingConfiguration(params), - ], - }, - ], - verify: (params: Params) => [ - { - type: StepType.VERIFY, - content: [ - { - type: 'text', - text: t( - 'You can verify your setup by intentionally causing an error that breaks your application:' - ), - }, - { - type: 'code', - language: 'python', - code: 'division_by_zero = 1 / 0', - }, - getVerifyLogsContent(params), - ], - }, - ], - nextSteps: (params: Params) => { - const steps = []; - - if (params.isLogsSelected) { - steps.push({ - id: 'logs', - name: t('Logging Integrations'), - description: t( - 'Add logging integrations to automatically capture logs from your application.' - ), - link: 'https://docs.sentry.io/platforms/python/logs/#integrations', - }); - } - - return steps; - }, -}; - -export const crashReportOnboardingPython: OnboardingConfig = { - introduction: () => getCrashReportModalIntroduction(), - install: (params: Params) => getCrashReportBackendInstallSteps(params), - configure: () => [ - { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: getCrashReportModalConfigDescription({ - link: 'https://docs.sentry.io/platforms/python/user-feedback/configuration/#crash-report-modal', - }), - }, - ], - }, - ], - verify: () => [], - nextSteps: () => [], -}; - -export const performanceOnboarding: OnboardingConfig = { - introduction: () => - t( - "Adding Performance to your Python project is simple. Make sure you've got these basics down." - ), - install: onboarding.install, - configure: params => [ - { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: t( - "Configuration should happen as early as possible in your application's lifecycle." - ), - }, - { - type: 'text', - text: tct( - "Once this is done, Sentry's Python SDK captures all unhandled exceptions and transactions. To enable tracing, use [code:traces_sample_rate=1.0] in the sentry_sdk.init() call.", - {code: } - ), - }, - { - type: 'code', - language: 'python', - code: ` -import sentry_sdk - -sentry_sdk.init( - dsn="${params.dsn.public}", - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for tracing. - traces_sample_rate=1.0, -)`, - }, - { - type: 'text', - text: tct( - 'Learn more about tracing [linkTracingOptions:options], how to use the [linkTracesSampler:traces_sampler] function, or how to [linkSampleTransactions:sample transactions].', - { - linkTracingOptions: ( - - ), - linkTracesSampler: ( - - ), - linkSampleTransactions: ( - - ), - } - ), - }, - ], - }, - ], - verify: () => [ - { - type: StepType.VERIFY, - content: [ - { - type: 'text', - text: tct( - 'Verify that performance monitoring is working correctly with our [link:automatic instrumentation] by simply using your Python application.', - { - link: ( - - ), - } - ), - }, - { - type: 'text', - text: tct( - 'You have the option to manually construct a transaction using [link:custom instrumentation].', - { - link: ( - - ), - } - ), - }, - ], - }, - ], - nextSteps: () => [], -}; - -export const featureFlagOnboarding: OnboardingConfig = { - install: () => [], - configure: ({featureFlagOptions = {integration: ''}, dsn}) => { - const {integrationName, packageName, makeConfigureCode, makeVerifyCode} = - FEATURE_FLAG_CONFIGURATION_MAP[ - featureFlagOptions.integration as keyof typeof FEATURE_FLAG_CONFIGURATION_MAP - ]; - - return [ - { - type: StepType.INSTALL, - content: [ - { - type: 'text', - text: - featureFlagOptions.integration === FeatureFlagProviderEnum.GENERIC - ? t('Install the Sentry SDK.') - : t('Install the Sentry SDK with an extra.'), - }, - getPythonInstallCodeBlock({packageName}), - ], - }, - { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: - featureFlagOptions.integration === FeatureFlagProviderEnum.GENERIC - ? `You don't need an integration for a generic usecase. Simply use this API after initializing Sentry.` - : tct('Add [name] to your integrations list.', { - name: {`${integrationName}`}, - }), - }, - { - type: 'code', - language: 'python', - code: makeConfigureCode(dsn.public), - }, - ], - }, - { - type: StepType.VERIFY, - content: [ - { - type: 'text', - text: t( - 'Test your setup by evaluating a flag, then capturing an exception. Check the Feature Flags table in Issue Details to confirm that your error event has recorded the flag and its result.' - ), - }, - { - type: 'code', - language: 'python', - code: makeVerifyCode(), - }, - ], - }, - ]; - }, - verify: () => [], - nextSteps: () => [], -}; - -export const mcpOnboarding: OnboardingConfig = { - install: () => { - const packageName = 'sentry-sdk'; - - return [ - { - type: StepType.INSTALL, - content: [ - { - type: 'text', - text: t( - 'To enable MCP monitoring, you need to install the Sentry SDK with a minimum version of 2.43.0 or higher.' - ), - }, - getPythonInstallCodeBlock({packageName}), - ], - }, - ]; - }, - configure: (params: Params) => { - const mcpLowLevelStep: OnboardingStep = { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: t('Configure Sentry for MCP low-level monitoring:'), - }, - { - type: 'code', - language: 'python', - code: ` -import sentry_sdk -from sentry_sdk.integrations.mcp import MCPIntegration - -sentry_sdk.init( - dsn="${params.dsn.public}", - traces_sample_rate=1.0, - # Add data like inputs and responses to/from MCP servers; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[ - MCPIntegration(), - ], -)`, - }, - { - type: 'text', - text: t('Set up your Low-level MCP server:'), - }, - { - type: 'code', - language: 'python', - code: ` -from mcp.server.lowlevel import Server -from mcp.types import Tool, TextContent - -server = Server("mcp-server") - -@server.list_tools() -async def list_tools() -> list[Tool]: - """List all available tools.""" - return [ - Tool( - name="calculate_sum", - description="Add two numbers together", - inputSchema={ - "type": "object", - "properties": { - "a": {"type": "number", "description": "First number"}, - "b": {"type": "number", "description": "Second number"}, - }, - "required": ["a", "b"], - }, - ) - ] -@server.call_tool() -async def call_tool(name: str, arguments) -> list[TextContent]: - """Handle tool execution based on tool name.""" - - if name == "calculate_sum": - a = arguments.get("a", 0) - b = arguments.get("b", 0) - result = a + b - return [TextContent(type="text", text=f"The sum of {a} and {b} is {result}")] - -`, - }, - ], - }; - - const mcpFastMcpStep: OnboardingStep = { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: t('Configure Sentry for MCP low-level monitoring:'), - }, - { - type: 'code', - language: 'python', - code: ` -import sentry_sdk -from sentry_sdk.integrations.mcp import MCPIntegration - -sentry_sdk.init( - dsn="${params.dsn.public}", - traces_sample_rate=1.0, - # Add data like inputs and responses to/from MCP servers; - # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info - send_default_pii=True, - integrations=[ - MCPIntegration(), - ], -)`, - }, - { - type: 'text', - text: t('Set up your FastMCP server:'), - }, - { - type: 'code', - language: 'python', - code: ` -from mcp.server.fastmcp import FastMCP -# from fastmcp import FastMCP if you are using the standalone version - -mcp = FastMCP("mcp-server") - -@mcp.tool() -async def calculate_sum(a: int, b: int) -> int: - """Add two numbers together.""" - return a + b -`, - }, - ], - }; - - const manualStep: OnboardingStep = { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: t('Configure Sentry for manual MCP instrumentation:'), - }, - { - type: 'code', - language: 'python', - code: ` -import sentry_sdk - -sentry_sdk.init( - dsn="${params.dsn.public}", - traces_sample_rate=1.0, -) -`, - }, - ], - }; - - const selected = (params.platformOptions as any)?.integration ?? 'mcp_fastmcp'; - if (selected === 'mcp_fastmcp') { - return [mcpFastMcpStep]; - } - if (selected === 'manual') { - return [manualStep]; - } - return [mcpLowLevelStep]; - }, - verify: (params: Params) => { - const mcpVerifyStep: OnboardingStep = { - type: StepType.VERIFY, - content: [ - { - type: 'text', - text: t( - 'Verify that MCP monitoring is working correctly by triggering some MCP server interactions in your application.' - ), - }, - ], - }; - - const manualVerifyStep: OnboardingStep = { - type: StepType.VERIFY, - content: [ - { - type: 'text', - text: t( - 'Verify that MCP monitoring is working correctly by running your manually instrumented code:' - ), - }, - { - type: 'code', - language: 'python', - code: ` -import json -import sentry_sdk - -# Invoke Agent span -with sentry_sdk.start_span(op="mcp.server", name="tools/call calculate_sum") as span: - span.set_data("mcp.method.name", "tools/call") - span.set_data("mcp.request.argument.a", "1") - span.set_data("mcp.request.argument.b", "2") - span.set_data("mcp.request.id", 123) - span.set_data("mcp.session.id", "c6d1c6a4c35843d5bdf0f9d88d11c183") - span.set_data("mcp.tool.name", "calculate_sum") - span.set_data("mcp.tool.result.content_count", 1) - span.set_data("mcp.transport", "stdio") -`, - }, - ], - }; - const selected = (params.platformOptions as any)?.integration ?? 'mcp_fastmcp'; - if (selected === 'manual') { - return [manualVerifyStep]; - } - return [mcpVerifyStep]; - }, - nextSteps: () => [], -}; - -export const agentMonitoringOnboarding: OnboardingConfig = { - install: (params: Params) => { +export const agentMonitoring: OnboardingConfig = { + install: params => { const selected = (params.platformOptions as any)?.integration ?? 'openai_agents'; let packageName = 'sentry-sdk'; @@ -699,7 +38,7 @@ export const agentMonitoringOnboarding: OnboardingConfig = { }, ]; }, - configure: (params: Params) => { + configure: params => { const openaiAgentsStep: OnboardingStep = { type: StepType.CONFIGURE, content: [ @@ -1050,7 +389,7 @@ sentry_sdk.init( } return [openaiAgentsStep]; }, - verify: (params: Params) => { + verify: params => { const openaiAgentsVerifyStep: OnboardingStep = { type: StepType.VERIFY, content: [ @@ -1394,19 +733,5 @@ with sentry_sdk.start_span(op="gen_ai.chat", name="chat o3-mini") as span: } return [openaiAgentsVerifyStep]; }, + nextSteps: () => [], }; - -const logsOnboarding = getPythonLogsOnboarding(); - -const docs: Docs = { - onboarding, - performanceOnboarding, - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, - profilingOnboarding: getPythonProfilingOnboarding({traceLifecycle: 'manual'}), - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, -}; - -export default docs; diff --git a/static/app/gettingStartedDocs/python/python/crashReport.tsx b/static/app/gettingStartedDocs/python/python/crashReport.tsx new file mode 100644 index 00000000000000..b0b90c060e3d38 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/crashReport.tsx @@ -0,0 +1,27 @@ +import type {OnboardingConfig} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import { + getCrashReportBackendInstallSteps, + getCrashReportModalConfigDescription, + getCrashReportModalIntroduction, +} from 'sentry/components/onboarding/gettingStartedDoc/utils/feedbackOnboarding'; + +export const crashReport: OnboardingConfig = { + introduction: () => getCrashReportModalIntroduction(), + install: params => getCrashReportBackendInstallSteps(params), + configure: () => [ + { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: getCrashReportModalConfigDescription({ + link: 'https://docs.sentry.io/platforms/python/user-feedback/configuration/#crash-report-modal', + }), + }, + ], + }, + ], + verify: () => [], + nextSteps: () => [], +}; diff --git a/static/app/gettingStartedDocs/python/python/featureFlag.tsx b/static/app/gettingStartedDocs/python/python/featureFlag.tsx new file mode 100644 index 00000000000000..a746a9a0afca96 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/featureFlag.tsx @@ -0,0 +1,188 @@ +import {SdkProviderEnum as FeatureFlagProviderEnum} from 'sentry/components/events/featureFlags/utils'; +import type {OnboardingConfig} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t, tct} from 'sentry/locale'; + +import {getPythonInstallCodeBlock} from './utils'; + +type FeatureFlagConfiguration = { + integrationName: string; + makeConfigureCode: (dsn: string) => string; + makeVerifyCode: () => string; + packageName: string; +}; + +const FEATURE_FLAG_CONFIGURATION_MAP: Record< + FeatureFlagProviderEnum, + FeatureFlagConfiguration +> = { + [FeatureFlagProviderEnum.GENERIC]: { + integrationName: ``, + packageName: 'sentry-sdk', + makeConfigureCode: (dsn: string) => `sentry_sdk.init( + dsn="${dsn}", + # Add data like request headers and IP for users, if applicable; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[ + # your other integrations here + ], +)`, + makeVerifyCode: () => `import sentry_sdk +from sentry_sdk.feature_flags import add_feature_flag + +add_feature_flag('test-flag', False) # Records an evaluation and its result. +sentry_sdk.capture_exception(Exception("Something went wrong!"))`, + }, + + [FeatureFlagProviderEnum.LAUNCHDARKLY]: { + integrationName: `LaunchDarklyIntegration`, + packageName: "'sentry-sdk[launchdarkly]'", + makeConfigureCode: (dsn: string) => `import sentry_sdk +from sentry_sdk.integrations.launchdarkly import LaunchDarklyIntegration +import ldclient + +sentry_sdk.init( + dsn="${dsn}", + # Add data like request headers and IP for users, if applicable; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[ + LaunchDarklyIntegration(), + ], +)`, + makeVerifyCode: () => `client = ldclient.get() +client.variation("hello", Context.create("test-context"), False) # Evaluate a flag with a default value. +sentry_sdk.capture_exception(Exception("Something went wrong!"))`, + }, + + [FeatureFlagProviderEnum.OPENFEATURE]: { + integrationName: `OpenFeatureIntegration`, + packageName: "'sentry-sdk[openfeature]'", + makeConfigureCode: (dsn: string) => `import sentry_sdk +from sentry_sdk.integrations.openfeature import OpenFeatureIntegration +from openfeature import api + +sentry_sdk.init( + dsn="${dsn}", + # Add data like request headers and IP for users, if applicable; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[ + OpenFeatureIntegration(), + ], +)`, + makeVerifyCode: () => `client = api.get_client() +client.get_boolean_value("hello", default_value=False) # Evaluate a flag with a default value. +sentry_sdk.capture_exception(Exception("Something went wrong!"))`, + }, + + [FeatureFlagProviderEnum.STATSIG]: { + integrationName: `StatsigIntegration`, + packageName: "'sentry-sdk[statsig]'", + makeConfigureCode: (dsn: string) => `import sentry_sdk +from sentry_sdk.integrations.statsig import StatsigIntegration +from statsig.statsig_user import StatsigUser +from statsig import statsig +import time + +sentry_sdk.init( + dsn="${dsn}", + # Add data like request headers and IP for users, if applicable; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[StatsigIntegration()], +) +statsig.initialize("server-secret-key")`, + makeVerifyCode: () => `while not statsig.is_initialized(): + time.sleep(0.2) + +result = statsig.check_gate(StatsigUser("my-user-id"), "my-feature-gate") # Evaluate a flag. +sentry_sdk.capture_exception(Exception("Something went wrong!"))`, + }, + + [FeatureFlagProviderEnum.UNLEASH]: { + integrationName: `UnleashIntegration`, + packageName: "'sentry-sdk[unleash]'", + makeConfigureCode: (dsn: string) => `import sentry_sdk +from sentry_sdk.integrations.unleash import UnleashIntegration +from UnleashClient import UnleashClient + +sentry_sdk.init( + dsn="${dsn}", + # Add data like request headers and IP for users, if applicable; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[UnleashIntegration()], +) + +unleash = UnleashClient(...) # See Unleash quickstart. +unleash.initialize_client()`, + makeVerifyCode: + () => `test_flag_enabled = unleash.is_enabled("test-flag") # Evaluate a flag. +sentry_sdk.capture_exception(Exception("Something went wrong!"))`, + }, +}; + +export const featureFlag: OnboardingConfig = { + install: () => [], + configure: ({featureFlagOptions = {integration: ''}, dsn}) => { + const {integrationName, packageName, makeConfigureCode, makeVerifyCode} = + FEATURE_FLAG_CONFIGURATION_MAP[ + featureFlagOptions.integration as keyof typeof FEATURE_FLAG_CONFIGURATION_MAP + ]; + + return [ + { + type: StepType.INSTALL, + content: [ + { + type: 'text', + text: + featureFlagOptions.integration === FeatureFlagProviderEnum.GENERIC + ? t('Install the Sentry SDK.') + : t('Install the Sentry SDK with an extra.'), + }, + getPythonInstallCodeBlock({packageName}), + ], + }, + { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: + featureFlagOptions.integration === FeatureFlagProviderEnum.GENERIC + ? `You don't need an integration for a generic usecase. Simply use this API after initializing Sentry.` + : tct('Add [name] to your integrations list.', { + name: {`${integrationName}`}, + }), + }, + { + type: 'code', + language: 'python', + code: makeConfigureCode(dsn.public), + }, + ], + }, + { + type: StepType.VERIFY, + content: [ + { + type: 'text', + text: t( + 'Test your setup by evaluating a flag, then capturing an exception. Check the Feature Flags table in Issue Details to confirm that your error event has recorded the flag and its result.' + ), + }, + { + type: 'code', + language: 'python', + code: makeVerifyCode(), + }, + ], + }, + ]; + }, + verify: () => [], + nextSteps: () => [], +}; diff --git a/static/app/gettingStartedDocs/python/python/index.tsx b/static/app/gettingStartedDocs/python/python/index.tsx new file mode 100644 index 00000000000000..ac6257d903201d --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/index.tsx @@ -0,0 +1,23 @@ +import type {Docs} from 'sentry/components/onboarding/gettingStartedDoc/types'; + +import {agentMonitoring} from './agentMonitoring'; +import {crashReport} from './crashReport'; +import {featureFlag} from './featureFlag'; +import {logs} from './logs'; +import {mcp} from './mcp'; +import {onboarding} from './onboarding'; +import {performance} from './performance'; +import {profiling} from './profiling'; + +const docs: Docs = { + onboarding, + performanceOnboarding: performance, + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, + profilingOnboarding: profiling({traceLifecycle: 'manual'}), + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs(), +}; + +export default docs; diff --git a/static/app/gettingStartedDocs/python/python/logs.spec.tsx b/static/app/gettingStartedDocs/python/python/logs.spec.tsx new file mode 100644 index 00000000000000..736f2f4a9c51dc --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/logs.spec.tsx @@ -0,0 +1,47 @@ +// Only import and test functions that don't have circular dependencies +const {logs} = jest.requireActual('sentry/gettingStartedDocs/python/python/logs'); + +describe('logs', () => { + const mockParams = { + dsn: { + public: 'https://test@example.com/123', + }, + }; + + it('generates logs onboarding config with default parameters', () => { + const result = logs(); + + // Test install step + const installSteps = result.install(); + expect(installSteps).toHaveLength(1); + expect(installSteps[0].type).toBe('install'); + expect(installSteps[0].content).toHaveLength(2); + + // Test configure step + const configureSteps = result.configure(mockParams); + expect(configureSteps).toHaveLength(1); + expect(configureSteps[0].type).toBe('configure'); + expect(configureSteps[0].content[1].code).toContain('enable_logs=True'); + expect(configureSteps[0].content[1].code).toContain(mockParams.dsn.public); + + // Test verify step + const verifySteps = result.verify({isLogsSelected: true}); + expect(verifySteps).toHaveLength(1); + expect(verifySteps[0].type).toBe('verify'); + expect(verifySteps[0].content).toHaveLength(1); + expect(verifySteps[0].content[0].type).toBe('conditional'); + const conditionalContent = verifySteps[0].content[0].content; + expect(conditionalContent[1].code).toContain('sentry_sdk.logger.info'); + expect(conditionalContent[3].code).toContain('import logging'); + }); + + it('generates logs onboarding config with custom parameters', () => { + const result = logs({ + packageName: 'custom-sentry-sdk', + minimumVersion: '3.0.0', + }); + + const installSteps = result.install(); + expect(installSteps[0].content).toHaveLength(2); + }); +}); diff --git a/static/app/gettingStartedDocs/python/python/logs.tsx b/static/app/gettingStartedDocs/python/python/logs.tsx new file mode 100644 index 00000000000000..a30e76110af0a7 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/logs.tsx @@ -0,0 +1,120 @@ +import {ExternalLink} from 'sentry/components/core/link'; +import { + StepType, + type ContentBlock, + type DocsParams, + type OnboardingConfig, +} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t, tct} from 'sentry/locale'; + +import {getPythonInstallCodeBlock} from './utils'; + +export const verify = (params: DocsParams): ContentBlock => ({ + type: 'conditional', + condition: params.isLogsSelected, + content: [ + { + type: 'text', + text: t('You can send logs to Sentry using the Sentry logging APIs:'), + }, + { + type: 'code', + language: 'python', + code: `import sentry_sdk + +# Send logs directly to Sentry +sentry_sdk.logger.info('This is an info log message') +sentry_sdk.logger.warning('This is a warning message') +sentry_sdk.logger.error('This is an error message')`, + }, + { + type: 'text', + text: t( + "You can also use Python's built-in logging module, which will automatically forward logs to Sentry:" + ), + }, + { + type: 'code', + language: 'python', + code: `import logging + +# Your existing logging setup +logger = logging.getLogger(__name__) + +# These logs will be automatically sent to Sentry +logger.info('This will be sent to Sentry') +logger.warning('User login failed') +logger.error('Something went wrong')`, + }, + ], +}); + +export const logs = ({ + packageName = 'sentry-sdk', +}: { + packageName?: string; +} = {}): OnboardingConfig => ({ + install: () => [ + { + type: StepType.INSTALL, + content: [ + { + type: 'text', + text: tct( + 'Install our Python SDK with a minimum version that supports logs ([code:2.35.0] or higher).', + { + code: , + } + ), + }, + getPythonInstallCodeBlock({ + packageName, + minimumVersion: '2.35.0', + }), + ], + }, + ], + configure: (params: DocsParams) => [ + { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: tct( + 'Configure the Sentry SDK to capture logs by setting [code:enable_logs=True] in your [code:sentry_sdk.init()] call:', + { + code: , + } + ), + }, + { + type: 'code', + language: 'python', + code: `import sentry_sdk + +sentry_sdk.init( + dsn="${params.dsn.public}", + # Enable logs to be sent to Sentry + enable_logs=True, +)`, + }, + { + type: 'text', + text: tct( + 'For more detailed information on logging configuration, see the [link:logs documentation].', + { + link: , + } + ), + }, + ], + }, + ], + verify: (params: DocsParams) => [ + { + type: StepType.VERIFY, + description: t('Test that logs are working by sending some test logs:'), + content: [verify(params)], + }, + ], +}); diff --git a/static/app/gettingStartedDocs/python/python/mcp.tsx b/static/app/gettingStartedDocs/python/python/mcp.tsx new file mode 100644 index 00000000000000..890c4042ae4bcd --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/mcp.tsx @@ -0,0 +1,228 @@ +import type { + OnboardingConfig, + OnboardingStep, +} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t} from 'sentry/locale'; + +import {getPythonInstallCodeBlock} from './utils'; + +export const mcp: OnboardingConfig = { + install: () => { + const packageName = 'sentry-sdk'; + + return [ + { + type: StepType.INSTALL, + content: [ + { + type: 'text', + text: t( + 'To enable MCP monitoring, you need to install the Sentry SDK with a minimum version of 2.43.0 or higher.' + ), + }, + getPythonInstallCodeBlock({packageName}), + ], + }, + ]; + }, + configure: params => { + const mcpLowLevelStep: OnboardingStep = { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: t('Configure Sentry for MCP low-level monitoring:'), + }, + { + type: 'code', + language: 'python', + code: ` +import sentry_sdk +from sentry_sdk.integrations.mcp import MCPIntegration + +sentry_sdk.init( + dsn="${params.dsn.public}", + traces_sample_rate=1.0, + # Add data like inputs and responses to/from MCP servers; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[ + MCPIntegration(), + ], +)`, + }, + { + type: 'text', + text: t('Set up your Low-level MCP server:'), + }, + { + type: 'code', + language: 'python', + code: ` +from mcp.server.lowlevel import Server +from mcp.types import Tool, TextContent + +server = Server("mcp-server") + +@server.list_tools() +async def list_tools() -> list[Tool]: + """List all available tools.""" + return [ + Tool( + name="calculate_sum", + description="Add two numbers together", + inputSchema={ + "type": "object", + "properties": { + "a": {"type": "number", "description": "First number"}, + "b": {"type": "number", "description": "Second number"}, + }, + "required": ["a", "b"], + }, + ) + ] +@server.call_tool() +async def call_tool(name: str, arguments) -> list[TextContent]: + """Handle tool execution based on tool name.""" + + if name == "calculate_sum": + a = arguments.get("a", 0) + b = arguments.get("b", 0) + result = a + b + return [TextContent(type="text", text=f"The sum of {a} and {b} is {result}")] + +`, + }, + ], + }; + + const mcpFastMcpStep: OnboardingStep = { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: t('Configure Sentry for MCP low-level monitoring:'), + }, + { + type: 'code', + language: 'python', + code: ` +import sentry_sdk +from sentry_sdk.integrations.mcp import MCPIntegration + +sentry_sdk.init( + dsn="${params.dsn.public}", + traces_sample_rate=1.0, + # Add data like inputs and responses to/from MCP servers; + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True, + integrations=[ + MCPIntegration(), + ], +)`, + }, + { + type: 'text', + text: t('Set up your FastMCP server:'), + }, + { + type: 'code', + language: 'python', + code: ` +from mcp.server.fastmcp import FastMCP +# from fastmcp import FastMCP if you are using the standalone version + +mcp = FastMCP("mcp-server") + +@mcp.tool() +async def calculate_sum(a: int, b: int) -> int: + """Add two numbers together.""" + return a + b +`, + }, + ], + }; + + const manualStep: OnboardingStep = { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: t('Configure Sentry for manual MCP instrumentation:'), + }, + { + type: 'code', + language: 'python', + code: ` +import sentry_sdk + +sentry_sdk.init( + dsn="${params.dsn.public}", + traces_sample_rate=1.0, +) +`, + }, + ], + }; + + const selected = (params.platformOptions as any)?.integration ?? 'mcp_fastmcp'; + if (selected === 'mcp_fastmcp') { + return [mcpFastMcpStep]; + } + if (selected === 'manual') { + return [manualStep]; + } + return [mcpLowLevelStep]; + }, + verify: params => { + const mcpVerifyStep: OnboardingStep = { + type: StepType.VERIFY, + content: [ + { + type: 'text', + text: t( + 'Verify that MCP monitoring is working correctly by triggering some MCP server interactions in your application.' + ), + }, + ], + }; + + const manualVerifyStep: OnboardingStep = { + type: StepType.VERIFY, + content: [ + { + type: 'text', + text: t( + 'Verify that MCP monitoring is working correctly by running your manually instrumented code:' + ), + }, + { + type: 'code', + language: 'python', + code: ` +import json +import sentry_sdk + +# Invoke Agent span +with sentry_sdk.start_span(op="mcp.server", name="tools/call calculate_sum") as span: + span.set_data("mcp.method.name", "tools/call") + span.set_data("mcp.request.argument.a", "1") + span.set_data("mcp.request.argument.b", "2") + span.set_data("mcp.request.id", 123) + span.set_data("mcp.session.id", "c6d1c6a4c35843d5bdf0f9d88d11c183") + span.set_data("mcp.tool.name", "calculate_sum") + span.set_data("mcp.tool.result.content_count", 1) + span.set_data("mcp.transport", "stdio") +`, + }, + ], + }; + const selected = (params.platformOptions as any)?.integration ?? 'mcp_fastmcp'; + if (selected === 'manual') { + return [manualVerifyStep]; + } + return [mcpVerifyStep]; + }, + nextSteps: () => [], +}; diff --git a/static/app/gettingStartedDocs/python/python.spec.tsx b/static/app/gettingStartedDocs/python/python/onboarding.spec.tsx similarity index 99% rename from static/app/gettingStartedDocs/python/python.spec.tsx rename to static/app/gettingStartedDocs/python/python/onboarding.spec.tsx index 8dc54eb2ef86ee..109fd3f7e08f4a 100644 --- a/static/app/gettingStartedDocs/python/python.spec.tsx +++ b/static/app/gettingStartedDocs/python/python/onboarding.spec.tsx @@ -6,7 +6,7 @@ import {textWithMarkupMatcher} from 'sentry-test/utils'; import {ProductSolution} from 'sentry/components/onboarding/gettingStartedDoc/types'; -import docs from './python'; +import docs from '.'; describe('python onboarding docs', () => { it('renders doc correctly', () => { diff --git a/static/app/gettingStartedDocs/python/python/onboarding.tsx b/static/app/gettingStartedDocs/python/python/onboarding.tsx new file mode 100644 index 00000000000000..66d3225bd321ac --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/onboarding.tsx @@ -0,0 +1,146 @@ +import type { + DocsParams, + OnboardingConfig, +} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t, tct} from 'sentry/locale'; + +import {verify} from './logs'; +import {alternativeProfiling} from './profiling'; +import {getPythonInstallCodeBlock} from './utils'; + +const getSdkSetupSnippet = (params: DocsParams) => ` +import sentry_sdk + +sentry_sdk.init( + dsn="${params.dsn.public}", + # Add data like request headers and IP for users, + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + send_default_pii=True,${ + params.isLogsSelected + ? ` + # Enable sending logs to Sentry + enable_logs=True,` + : '' + }${ + params.isPerformanceSelected + ? ` + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for tracing. + traces_sample_rate=1.0,` + : '' + }${ + params.isProfilingSelected && + params.profilingOptions?.defaultProfilingMode !== 'continuous' + ? ` + # Set profiles_sample_rate to 1.0 to profile 100% + # of sampled transactions. + # We recommend adjusting this value in production. + profiles_sample_rate=1.0,` + : params.isProfilingSelected && + params.profilingOptions?.defaultProfilingMode === 'continuous' + ? ` + # Set profile_session_sample_rate to 1.0 to profile 100% + # of profile sessions. + profile_session_sample_rate=1.0,` + : '' + } +)${ + params.isProfilingSelected && + params.profilingOptions?.defaultProfilingMode === 'continuous' + ? ` + +def slow_function(): + import time + time.sleep(0.1) + return "done" + +def fast_function(): + import time + time.sleep(0.05) + return "done" + +# Manually call start_profiler and stop_profiler +# to profile the code in between +sentry_sdk.profiler.start_profiler() + +for i in range(0, 10): + slow_function() + fast_function() + +# Calls to stop_profiler are optional - if you don't stop the profiler, it will keep profiling +# your application until the process exits or stop_profiler is called. +sentry_sdk.profiler.stop_profiler()` + : '' +}`; + +export const onboarding: OnboardingConfig = { + install: () => [ + { + type: StepType.INSTALL, + content: [ + { + type: 'text', + text: tct('Install our Python SDK:', { + code: , + }), + }, + getPythonInstallCodeBlock(), + ], + }, + ], + configure: params => [ + { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: t( + "Import and initialize the Sentry SDK early in your application's setup:" + ), + }, + { + type: 'code', + language: 'python', + code: getSdkSetupSnippet(params), + }, + alternativeProfiling(params), + ], + }, + ], + verify: params => [ + { + type: StepType.VERIFY, + content: [ + { + type: 'text', + text: t( + 'You can verify your setup by intentionally causing an error that breaks your application:' + ), + }, + { + type: 'code', + language: 'python', + code: 'division_by_zero = 1 / 0', + }, + verify(params), + ], + }, + ], + nextSteps: params => { + const steps = []; + + if (params.isLogsSelected) { + steps.push({ + id: 'logs', + name: t('Logging Integrations'), + description: t( + 'Add logging integrations to automatically capture logs from your application.' + ), + link: 'https://docs.sentry.io/platforms/python/logs/#integrations', + }); + } + + return steps; + }, +}; diff --git a/static/app/gettingStartedDocs/python/python/performance.tsx b/static/app/gettingStartedDocs/python/python/performance.tsx new file mode 100644 index 00000000000000..e4c29803362361 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/performance.tsx @@ -0,0 +1,94 @@ +import {ExternalLink} from 'sentry/components/core/link'; +import type {OnboardingConfig} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t, tct} from 'sentry/locale'; + +import {onboarding} from './onboarding'; + +export const performance: OnboardingConfig = { + introduction: () => + t( + "Adding Performance to your Python project is simple. Make sure you've got these basics down." + ), + install: onboarding.install, + configure: params => [ + { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: t( + "Configuration should happen as early as possible in your application's lifecycle." + ), + }, + { + type: 'text', + text: tct( + "Once this is done, Sentry's Python SDK captures all unhandled exceptions and transactions. To enable tracing, use [code:traces_sample_rate=1.0] in the sentry_sdk.init() call.", + {code: } + ), + }, + { + type: 'code', + language: 'python', + code: ` +import sentry_sdk + +sentry_sdk.init( + dsn="${params.dsn.public}", + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for tracing. + traces_sample_rate=1.0, +)`, + }, + { + type: 'text', + text: tct( + 'Learn more about tracing [linkTracingOptions:options], how to use the [linkTracesSampler:traces_sampler] function, or how to [linkSampleTransactions:sample transactions].', + { + linkTracingOptions: ( + + ), + linkTracesSampler: ( + + ), + linkSampleTransactions: ( + + ), + } + ), + }, + ], + }, + ], + verify: () => [ + { + type: StepType.VERIFY, + content: [ + { + type: 'text', + text: tct( + 'Verify that performance monitoring is working correctly with our [link:automatic instrumentation] by simply using your Python application.', + { + link: ( + + ), + } + ), + }, + { + type: 'text', + text: tct( + 'You have the option to manually construct a transaction using [link:custom instrumentation].', + { + link: ( + + ), + } + ), + }, + ], + }, + ], + nextSteps: () => [], +}; diff --git a/static/app/gettingStartedDocs/python/python/profiling.tsx b/static/app/gettingStartedDocs/python/python/profiling.tsx new file mode 100644 index 00000000000000..09fedcd1e2bfc6 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/profiling.tsx @@ -0,0 +1,167 @@ +import {ExternalLink} from 'sentry/components/core/link'; +import { + StepType, + type ContentBlock, + type DocsParams, + type OnboardingConfig, +} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {t, tct} from 'sentry/locale'; + +import {getPythonInstallCodeBlock} from './utils'; + +const getProfilingSdkSetupSnippet = ( + params: DocsParams, + traceLifecycle: 'manual' | 'trace' +) => ` +import sentry_sdk + +sentry_sdk.init( + dsn="${params.dsn.public}",${ + params.profilingOptions?.defaultProfilingMode === 'continuous' + ? traceLifecycle === 'trace' + ? ` + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for tracing. + traces_sample_rate=1.0, + # Set profile_session_sample_rate to 1.0 to profile 100% + # of profile sessions. + profile_session_sample_rate=1.0, + # Set profile_lifecycle to "trace" to automatically + # run the profiler on when there is an active transaction + profile_lifecycle="trace"` + : ` + # Tracing is not required for profiling to work + # but for the best experience we recommend enabling it + traces_sample_rate=1.0, + # Set profile_session_sample_rate to 1.0 to profile 100% + # of profile sessions. + profile_session_sample_rate=1.0` + : ` + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for tracing. + traces_sample_rate=1.0, + # Set profiles_sample_rate to 1.0 to profile 100% + # of sampled transactions. + # We recommend adjusting this value in production. + profiles_sample_rate=1.0` + } +)${ + params.profilingOptions?.defaultProfilingMode === 'continuous' && + traceLifecycle === 'manual' + ? ` + +def slow_function(): + import time + time.sleep(0.1) + return "done" + +def fast_function(): + import time + time.sleep(0.05) + return "done" + +# Manually call start_profiler and stop_profiler +# to profile the code in between +sentry_sdk.profiler.start_profiler() + +for i in range(0, 10): + slow_function() + fast_function() + +# Calls to stop_profiler are optional - if you don't stop the profiler, it will keep profiling +# your application until the process exits or stop_profiler is called. +sentry_sdk.profiler.stop_profiler()` + : '' +}`; + +export const alternativeProfiling = (params: DocsParams): ContentBlock => ({ + type: 'conditional', + condition: + params.isProfilingSelected && + params.profilingOptions?.defaultProfilingMode === 'continuous', + content: [ + { + type: 'text', + text: tct( + 'Alternatively, you can also explicitly control continuous profiling or use transaction profiling. See our [link:documentation] for more information.', + { + link: ( + + ), + } + ), + }, + ], +}); + +export const profiling = ({ + basePackage = 'sentry-sdk', + traceLifecycle = 'trace', +}: { + basePackage?: string; + traceLifecycle?: 'manual' | 'trace'; +} = {}): OnboardingConfig => ({ + install: () => [ + { + type: StepType.INSTALL, + content: [ + { + type: 'text', + text: tct( + 'To enable profiling, update the Sentry SDK to a compatible version ([code:2.24.1] or higher).', + { + code: , + } + ), + }, + getPythonInstallCodeBlock({ + packageName: basePackage, + minimumVersion: '2.24.1', + }), + ], + }, + ], + configure: (params: DocsParams) => [ + { + type: StepType.CONFIGURE, + content: [ + { + type: 'text', + text: t( + "Import and initialize the Sentry SDK early in your application's setup:" + ), + }, + { + type: 'code', + language: 'python', + code: getProfilingSdkSetupSnippet(params, traceLifecycle), + }, + { + type: 'text', + text: tct( + 'For more detailed information on profiling, see the [link:profiling documentation].', + { + link: ( + + ), + } + ), + }, + alternativeProfiling(params), + ], + }, + ], + verify: () => [ + { + type: StepType.VERIFY, + content: [ + { + type: 'text', + text: t( + 'Verify that profiling is working correctly by simply using your application.' + ), + }, + ], + }, + ], +}); diff --git a/static/app/gettingStartedDocs/python/python/utils.spec.tsx b/static/app/gettingStartedDocs/python/python/utils.spec.tsx new file mode 100644 index 00000000000000..bfb98d6ed93341 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/utils.spec.tsx @@ -0,0 +1,57 @@ +import {getPythonInstallCodeBlock} from './utils'; + +describe('getPythonInstallCodeBlock', () => { + it('generates install commands with default parameters', () => { + const result = getPythonInstallCodeBlock({ + packageName: 'sentry-sdk', + }); + + expect(result).toEqual({ + type: 'code', + tabs: [ + { + label: 'pip', + language: 'bash', + code: `pip install "sentry-sdk"`, + }, + { + label: 'uv', + language: 'bash', + code: `uv add "sentry-sdk"`, + }, + { + label: 'poetry', + language: 'bash', + code: `poetry add "sentry-sdk"`, + }, + ], + }); + }); + + it('generates pip install command with minimum version and extras', () => { + const result = getPythonInstallCodeBlock({ + packageName: 'sentry-sdk[with-extras]', + minimumVersion: '2.3.4', + }); + expect(result).toEqual({ + type: 'code', + tabs: [ + { + label: 'pip', + language: 'bash', + code: `pip install --upgrade "sentry-sdk[with-extras]>=2.3.4"`, + }, + { + label: 'uv', + language: 'bash', + code: `uv add --upgrade "sentry-sdk[with-extras]>=2.3.4"`, + }, + { + label: 'poetry', + language: 'bash', + code: `poetry add "sentry-sdk[with-extras]>=2.3.4"`, + }, + ], + }); + }); +}); diff --git a/static/app/gettingStartedDocs/python/python/utils.tsx b/static/app/gettingStartedDocs/python/python/utils.tsx new file mode 100644 index 00000000000000..8b762a3215da10 --- /dev/null +++ b/static/app/gettingStartedDocs/python/python/utils.tsx @@ -0,0 +1,79 @@ +import {type ContentBlock} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {tct} from 'sentry/locale'; + +function getPythonInstallSnippet({ + packageName, + minimumVersion, +}: { + packageName: string; + minimumVersion?: string; +}) { + // We are using consistent double quotes here for all package managers after aligning with the Python SDK team. + // Not using quotes may lead to some shells interpreting the square brackets, and using double quotes over single quotes is a convention. + const versionedPackage = minimumVersion + ? `"${packageName}>=${minimumVersion}"` + : `"${packageName}"`; + + const upgradeFlag = minimumVersion ? '--upgrade ' : ''; + + const packageManagerCommands = { + uv: `uv add ${upgradeFlag}${versionedPackage}`, + pip: `pip install ${upgradeFlag}${versionedPackage}`, + poetry: `poetry add ${versionedPackage}`, + }; + + return packageManagerCommands; +} + +export function getPythonInstallCodeBlock({ + packageName = 'sentry-sdk', + minimumVersion, +}: { + minimumVersion?: string; + packageName?: string; +} = {}): ContentBlock { + const packageManagerCommands = getPythonInstallSnippet({packageName, minimumVersion}); + return { + type: 'code', + tabs: [ + { + label: 'pip', + language: 'bash', + code: packageManagerCommands.pip, + }, + { + label: 'uv', + language: 'bash', + code: packageManagerCommands.uv, + }, + { + label: 'poetry', + language: 'bash', + code: packageManagerCommands.poetry, + }, + ], + }; +} + +export function getPythonAiocontextvarsCodeBlocks({ + description, +}: { + description?: React.ReactNode; +} = {}): ContentBlock[] { + const defaultDescription = tct( + "If you're on Python 3.6, you also need the [code:aiocontextvars] package:", + { + code: , + } + ); + + return [ + { + type: 'text', + text: description ?? defaultDescription, + }, + getPythonInstallCodeBlock({ + packageName: 'aiocontextvars', + }), + ]; +} diff --git a/static/app/gettingStartedDocs/python/quart.tsx b/static/app/gettingStartedDocs/python/quart.tsx index 91dc6c9c6e514f..9c062f6df577b9 100644 --- a/static/app/gettingStartedDocs/python/quart.tsx +++ b/static/app/gettingStartedDocs/python/quart.tsx @@ -9,20 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -108,7 +105,7 @@ ${getSdkSetupSnippet(params)} app = Quart(__name__) `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -137,7 +134,7 @@ async def hello(): app.run() `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -172,21 +169,18 @@ app.run() }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[quart]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[quart]'}), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[quart]'}), + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[quart]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/rq.tsx b/static/app/gettingStartedDocs/python/rq.tsx index 47557cc27ea47e..a386ce7e2453d8 100644 --- a/static/app/gettingStartedDocs/python/rq.tsx +++ b/static/app/gettingStartedDocs/python/rq.tsx @@ -5,17 +5,15 @@ import type { OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs} from 'sentry/gettingStartedDocs/python/python/logs'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -163,7 +161,7 @@ const onboarding: OnboardingConfig = { {code: } ), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -245,16 +243,14 @@ const onboarding: OnboardingConfig = { ], }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[rq]', -}); - const docs: Docs = { onboarding, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[rq]'}), - crashReportOnboarding: crashReportOnboardingPython, - agentMonitoringOnboarding, - logsOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[rq]'}), + crashReportOnboarding: crashReport, + agentMonitoringOnboarding: agentMonitoring, + logsOnboarding: logs({ + packageName: 'sentry-sdk[rq]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/sanic.tsx b/static/app/gettingStartedDocs/python/sanic.tsx index 1bfb9752d7eabf..9bdb397980b9ed 100644 --- a/static/app/gettingStartedDocs/python/sanic.tsx +++ b/static/app/gettingStartedDocs/python/sanic.tsx @@ -9,19 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; -import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; -import {t, tct} from 'sentry/locale'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; +import {profiling} from 'sentry/gettingStartedDocs/python/python/profiling'; import { getPythonAiocontextvarsCodeBlocks, getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, -} from 'sentry/utils/gettingStartedDocs/python'; +} from 'sentry/gettingStartedDocs/python/python/utils'; +import {t, tct} from 'sentry/locale'; type Params = DocsParams; @@ -136,20 +134,18 @@ async def hello_world(request): }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[sanic]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({basePackage: 'sentry-sdk[sanic]'}), - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + profilingOnboarding: profiling({basePackage: 'sentry-sdk[sanic]'}), + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[sanic]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/serverless.tsx b/static/app/gettingStartedDocs/python/serverless.tsx index d4c3c22d1067bb..5ee1c98f5ad02a 100644 --- a/static/app/gettingStartedDocs/python/serverless.tsx +++ b/static/app/gettingStartedDocs/python/serverless.tsx @@ -7,17 +7,15 @@ import { type DocsParams, type OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {verify} from 'sentry/gettingStartedDocs/python/python/logs'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -124,7 +122,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -146,7 +144,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getVerifySnippet(), }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: t( @@ -174,9 +172,9 @@ const onboarding: OnboardingConfig = { const docs: Docs = { onboarding, - profilingOnboarding: getPythonProfilingOnboarding(), - crashReportOnboarding: crashReportOnboardingPython, - agentMonitoringOnboarding, + profilingOnboarding: profiling(), + crashReportOnboarding: crashReport, + agentMonitoringOnboarding: agentMonitoring, }; export default docs; diff --git a/static/app/gettingStartedDocs/python/starlette.tsx b/static/app/gettingStartedDocs/python/starlette.tsx index 7e398e4b110031..777d5c9bf05f84 100644 --- a/static/app/gettingStartedDocs/python/starlette.tsx +++ b/static/app/gettingStartedDocs/python/starlette.tsx @@ -9,19 +9,17 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -111,7 +109,7 @@ ${getSdkSetupSnippet(params)} app = Starlette(routes=[...]) `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -173,22 +171,20 @@ app = Starlette(routes=[ }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[starlette]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding({ + profilingOnboarding: profiling({ basePackage: 'sentry-sdk[starlette]', }), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[starlette]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/tornado.tsx b/static/app/gettingStartedDocs/python/tornado.tsx index c12c3a54791237..dfc4dce43a188c 100644 --- a/static/app/gettingStartedDocs/python/tornado.tsx +++ b/static/app/gettingStartedDocs/python/tornado.tsx @@ -9,21 +9,20 @@ import { feedbackOnboardingJsLoader, replayOnboardingJsLoader, } from 'sentry/gettingStartedDocs/javascript/jsLoader/jsLoader'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {featureFlag} from 'sentry/gettingStartedDocs/python/python/featureFlag'; +import {logs, verify} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - featureFlagOnboarding, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; -import {t, tct} from 'sentry/locale'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; import { - alternativeProfilingConfiguration, getPythonAiocontextvarsCodeBlocks, getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, - getVerifyLogsContent, -} from 'sentry/utils/gettingStartedDocs/python'; +} from 'sentry/gettingStartedDocs/python/python/utils'; +import {t, tct} from 'sentry/locale'; type Params = DocsParams; @@ -114,7 +113,7 @@ class MainHandler(tornado.web.RequestHandler): # ... `, }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -153,7 +152,7 @@ async def main(): asyncio.run(main()) `, }, - getVerifyLogsContent(params), + verify(params), { type: 'text', text: [ @@ -188,20 +187,18 @@ asyncio.run(main()) }, }; -const logsOnboarding = getPythonLogsOnboarding({ - packageName: 'sentry-sdk[tornado]', -}); - const docs: Docs = { onboarding, replayOnboardingJsLoader, - profilingOnboarding: getPythonProfilingOnboarding(), - crashReportOnboarding: crashReportOnboardingPython, - featureFlagOnboarding, + profilingOnboarding: profiling(), + crashReportOnboarding: crashReport, + featureFlagOnboarding: featureFlag, feedbackOnboardingJsLoader, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs({ + packageName: 'sentry-sdk[tornado]', + }), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/tryton.tsx b/static/app/gettingStartedDocs/python/tryton.tsx index 561c272bd7a955..7e84ecaa796b3d 100644 --- a/static/app/gettingStartedDocs/python/tryton.tsx +++ b/static/app/gettingStartedDocs/python/tryton.tsx @@ -5,17 +5,13 @@ import type { OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types'; -import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; +import {alternativeProfiling} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -139,15 +135,13 @@ const onboarding: OnboardingConfig = { }, ], }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], verify: () => [], }; -const logsOnboarding = getPythonLogsOnboarding(); - const profilingOnboarding: OnboardingConfig = { install: onboarding.install, configure: onboarding.configure, @@ -169,10 +163,10 @@ const profilingOnboarding: OnboardingConfig = { const docs: Docs = { onboarding, profilingOnboarding, - crashReportOnboarding: crashReportOnboardingPython, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + crashReportOnboarding: crashReport, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/gettingStartedDocs/python/wsgi.tsx b/static/app/gettingStartedDocs/python/wsgi.tsx index 88a92d40a53f6b..a2671406e4e605 100644 --- a/static/app/gettingStartedDocs/python/wsgi.tsx +++ b/static/app/gettingStartedDocs/python/wsgi.tsx @@ -7,18 +7,16 @@ import { type DocsParams, type OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; +import {agentMonitoring} from 'sentry/gettingStartedDocs/python/python/agentMonitoring'; +import {crashReport} from 'sentry/gettingStartedDocs/python/python/crashReport'; +import {logs} from 'sentry/gettingStartedDocs/python/python/logs'; +import {mcp} from 'sentry/gettingStartedDocs/python/python/mcp'; import { - agentMonitoringOnboarding, - crashReportOnboardingPython, - mcpOnboarding, -} from 'sentry/gettingStartedDocs/python/python'; + alternativeProfiling, + profiling, +} from 'sentry/gettingStartedDocs/python/python/profiling'; +import {getPythonInstallCodeBlock} from 'sentry/gettingStartedDocs/python/python/utils'; import {t, tct} from 'sentry/locale'; -import { - alternativeProfilingConfiguration, - getPythonInstallCodeBlock, - getPythonLogsOnboarding, - getPythonProfilingOnboarding, -} from 'sentry/utils/gettingStartedDocs/python'; type Params = DocsParams; @@ -135,7 +133,7 @@ const onboarding: OnboardingConfig = { language: 'python', code: getSdkSetupSnippet(params), }, - alternativeProfilingConfiguration(params), + alternativeProfiling(params), ], }, ], @@ -188,15 +186,13 @@ const onboarding: OnboardingConfig = { }, }; -const logsOnboarding = getPythonLogsOnboarding(); - const docs: Docs = { onboarding, - profilingOnboarding: getPythonProfilingOnboarding(), - crashReportOnboarding: crashReportOnboardingPython, - agentMonitoringOnboarding, - mcpOnboarding, - logsOnboarding, + profilingOnboarding: profiling(), + crashReportOnboarding: crashReport, + agentMonitoringOnboarding: agentMonitoring, + mcpOnboarding: mcp, + logsOnboarding: logs(), }; export default docs; diff --git a/static/app/utils/gettingStartedDocs/python.spec.tsx b/static/app/utils/gettingStartedDocs/python.spec.tsx deleted file mode 100644 index 87f467ff7ef7e9..00000000000000 --- a/static/app/utils/gettingStartedDocs/python.spec.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import {getPythonInstallCodeBlock} from 'sentry/utils/gettingStartedDocs/python'; - -// Only import and test functions that don't have circular dependencies -const {getPythonLogsOnboarding} = jest.requireActual( - 'sentry/utils/gettingStartedDocs/python' -); - -describe('getPythonInstallCodeBlock', () => { - it('generates install commands with default parameters', () => { - const result = getPythonInstallCodeBlock({ - packageName: 'sentry-sdk', - }); - - expect(result).toEqual({ - type: 'code', - tabs: [ - { - label: 'pip', - language: 'bash', - code: `pip install "sentry-sdk"`, - }, - { - label: 'uv', - language: 'bash', - code: `uv add "sentry-sdk"`, - }, - { - label: 'poetry', - language: 'bash', - code: `poetry add "sentry-sdk"`, - }, - ], - }); - }); - - it('generates pip install command with minimum version and extras', () => { - const result = getPythonInstallCodeBlock({ - packageName: 'sentry-sdk[with-extras]', - minimumVersion: '2.3.4', - }); - expect(result).toEqual({ - type: 'code', - tabs: [ - { - label: 'pip', - language: 'bash', - code: `pip install --upgrade "sentry-sdk[with-extras]>=2.3.4"`, - }, - { - label: 'uv', - language: 'bash', - code: `uv add --upgrade "sentry-sdk[with-extras]>=2.3.4"`, - }, - { - label: 'poetry', - language: 'bash', - code: `poetry add "sentry-sdk[with-extras]>=2.3.4"`, - }, - ], - }); - }); -}); - -describe('getPythonLogsOnboarding', () => { - const mockParams = { - dsn: { - public: 'https://test@example.com/123', - }, - }; - - it('generates logs onboarding config with default parameters', () => { - const result = getPythonLogsOnboarding(); - - // Test install step - const installSteps = result.install(); - expect(installSteps).toHaveLength(1); - expect(installSteps[0].type).toBe('install'); - expect(installSteps[0].content).toHaveLength(2); - - // Test configure step - const configureSteps = result.configure(mockParams); - expect(configureSteps).toHaveLength(1); - expect(configureSteps[0].type).toBe('configure'); - expect(configureSteps[0].content[1].code).toContain('enable_logs=True'); - expect(configureSteps[0].content[1].code).toContain(mockParams.dsn.public); - - // Test verify step - const verifySteps = result.verify({isLogsSelected: true}); - expect(verifySteps).toHaveLength(1); - expect(verifySteps[0].type).toBe('verify'); - expect(verifySteps[0].content).toHaveLength(1); - expect(verifySteps[0].content[0].type).toBe('conditional'); - const conditionalContent = verifySteps[0].content[0].content; - expect(conditionalContent[1].code).toContain('sentry_sdk.logger.info'); - expect(conditionalContent[3].code).toContain('import logging'); - }); - - it('generates logs onboarding config with custom parameters', () => { - const result = getPythonLogsOnboarding({ - packageName: 'custom-sentry-sdk', - minimumVersion: '3.0.0', - }); - - const installSteps = result.install(); - expect(installSteps[0].content).toHaveLength(2); - }); -}); diff --git a/static/app/utils/gettingStartedDocs/python.tsx b/static/app/utils/gettingStartedDocs/python.tsx deleted file mode 100644 index 55135c232429c2..00000000000000 --- a/static/app/utils/gettingStartedDocs/python.tsx +++ /dev/null @@ -1,352 +0,0 @@ -import {ExternalLink} from 'sentry/components/core/link'; -import { - StepType, - type ContentBlock, - type DocsParams, - type OnboardingConfig, -} from 'sentry/components/onboarding/gettingStartedDoc/types'; -import {t, tct} from 'sentry/locale'; - -function getPythonInstallSnippet({ - packageName, - minimumVersion, -}: { - packageName: string; - minimumVersion?: string; -}) { - // We are using consistent double quotes here for all package managers after aligning with the Python SDK team. - // Not using quotes may lead to some shells interpreting the square brackets, and using double quotes over single quotes is a convention. - const versionedPackage = minimumVersion - ? `"${packageName}>=${minimumVersion}"` - : `"${packageName}"`; - - const upgradeFlag = minimumVersion ? '--upgrade ' : ''; - - const packageManagerCommands = { - uv: `uv add ${upgradeFlag}${versionedPackage}`, - pip: `pip install ${upgradeFlag}${versionedPackage}`, - poetry: `poetry add ${versionedPackage}`, - }; - - return packageManagerCommands; -} - -export function getPythonInstallCodeBlock({ - packageName = 'sentry-sdk', - minimumVersion, -}: { - minimumVersion?: string; - packageName?: string; -} = {}): ContentBlock { - const packageManagerCommands = getPythonInstallSnippet({packageName, minimumVersion}); - return { - type: 'code', - tabs: [ - { - label: 'pip', - language: 'bash', - code: packageManagerCommands.pip, - }, - { - label: 'uv', - language: 'bash', - code: packageManagerCommands.uv, - }, - { - label: 'poetry', - language: 'bash', - code: packageManagerCommands.poetry, - }, - ], - }; -} - -export function getPythonAiocontextvarsCodeBlocks({ - description, -}: { - description?: React.ReactNode; -} = {}): ContentBlock[] { - const defaultDescription = tct( - "If you're on Python 3.6, you also need the [code:aiocontextvars] package:", - { - code: , - } - ); - - return [ - { - type: 'text', - text: description ?? defaultDescription, - }, - getPythonInstallCodeBlock({ - packageName: 'aiocontextvars', - }), - ]; -} - -export const getPythonLogsOnboarding = ({ - packageName = 'sentry-sdk', -}: { - packageName?: string; -} = {}): OnboardingConfig => ({ - install: () => [ - { - type: StepType.INSTALL, - content: [ - { - type: 'text', - text: tct( - 'Install our Python SDK with a minimum version that supports logs ([code:2.35.0] or higher).', - { - code: , - } - ), - }, - getPythonInstallCodeBlock({ - packageName, - minimumVersion: '2.35.0', - }), - ], - }, - ], - configure: (params: DocsParams) => [ - { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: tct( - 'Configure the Sentry SDK to capture logs by setting [code:enable_logs=True] in your [code:sentry_sdk.init()] call:', - { - code: , - } - ), - }, - { - type: 'code', - language: 'python', - code: `import sentry_sdk - -sentry_sdk.init( - dsn="${params.dsn.public}", - # Enable logs to be sent to Sentry - enable_logs=True, -)`, - }, - { - type: 'text', - text: tct( - 'For more detailed information on logging configuration, see the [link:logs documentation].', - { - link: , - } - ), - }, - ], - }, - ], - verify: (params: DocsParams) => [ - { - type: StepType.VERIFY, - description: t('Test that logs are working by sending some test logs:'), - content: [getVerifyLogsContent(params)], - }, - ], -}); - -export const getPythonProfilingOnboarding = ({ - basePackage = 'sentry-sdk', - traceLifecycle = 'trace', -}: { - basePackage?: string; - traceLifecycle?: 'manual' | 'trace'; -} = {}): OnboardingConfig => ({ - install: () => [ - { - type: StepType.INSTALL, - content: [ - { - type: 'text', - text: tct( - 'To enable profiling, update the Sentry SDK to a compatible version ([code:2.24.1] or higher).', - { - code: , - } - ), - }, - getPythonInstallCodeBlock({ - packageName: basePackage, - minimumVersion: '2.24.1', - }), - ], - }, - ], - configure: (params: DocsParams) => [ - { - type: StepType.CONFIGURE, - content: [ - { - type: 'text', - text: t( - "Import and initialize the Sentry SDK early in your application's setup:" - ), - }, - { - type: 'code', - language: 'python', - code: getProfilingSdkSetupSnippet(params, traceLifecycle), - }, - { - type: 'text', - text: tct( - 'For more detailed information on profiling, see the [link:profiling documentation].', - { - link: ( - - ), - } - ), - }, - alternativeProfilingConfiguration(params), - ], - }, - ], - verify: () => [ - { - type: StepType.VERIFY, - content: [ - { - type: 'text', - text: t( - 'Verify that profiling is working correctly by simply using your application.' - ), - }, - ], - }, - ], -}); - -const getProfilingSdkSetupSnippet = ( - params: DocsParams, - traceLifecycle: 'manual' | 'trace' -) => ` -import sentry_sdk - -sentry_sdk.init( - dsn="${params.dsn.public}",${ - params.profilingOptions?.defaultProfilingMode === 'continuous' - ? traceLifecycle === 'trace' - ? ` - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for tracing. - traces_sample_rate=1.0, - # Set profile_session_sample_rate to 1.0 to profile 100% - # of profile sessions. - profile_session_sample_rate=1.0, - # Set profile_lifecycle to "trace" to automatically - # run the profiler on when there is an active transaction - profile_lifecycle="trace"` - : ` - # Tracing is not required for profiling to work - # but for the best experience we recommend enabling it - traces_sample_rate=1.0, - # Set profile_session_sample_rate to 1.0 to profile 100% - # of profile sessions. - profile_session_sample_rate=1.0` - : ` - # Set traces_sample_rate to 1.0 to capture 100% - # of transactions for tracing. - traces_sample_rate=1.0, - # Set profiles_sample_rate to 1.0 to profile 100% - # of sampled transactions. - # We recommend adjusting this value in production. - profiles_sample_rate=1.0` - } -)${ - params.profilingOptions?.defaultProfilingMode === 'continuous' && - traceLifecycle === 'manual' - ? ` - -def slow_function(): - import time - time.sleep(0.1) - return "done" - -def fast_function(): - import time - time.sleep(0.05) - return "done" - -# Manually call start_profiler and stop_profiler -# to profile the code in between -sentry_sdk.profiler.start_profiler() - -for i in range(0, 10): - slow_function() - fast_function() - -# Calls to stop_profiler are optional - if you don't stop the profiler, it will keep profiling -# your application until the process exits or stop_profiler is called. -sentry_sdk.profiler.stop_profiler()` - : '' -}`; - -export const alternativeProfilingConfiguration = (params: DocsParams): ContentBlock => ({ - type: 'conditional', - condition: - params.isProfilingSelected && - params.profilingOptions?.defaultProfilingMode === 'continuous', - content: [ - { - type: 'text', - text: tct( - 'Alternatively, you can also explicitly control continuous profiling or use transaction profiling. See our [link:documentation] for more information.', - { - link: ( - - ), - } - ), - }, - ], -}); - -export const getVerifyLogsContent = (params: DocsParams): ContentBlock => ({ - type: 'conditional', - condition: params.isLogsSelected, - content: [ - { - type: 'text', - text: t('You can send logs to Sentry using the Sentry logging APIs:'), - }, - { - type: 'code', - language: 'python', - code: `import sentry_sdk - -# Send logs directly to Sentry -sentry_sdk.logger.info('This is an info log message') -sentry_sdk.logger.warning('This is a warning message') -sentry_sdk.logger.error('This is an error message')`, - }, - { - type: 'text', - text: t( - "You can also use Python's built-in logging module, which will automatically forward logs to Sentry:" - ), - }, - { - type: 'code', - language: 'python', - code: `import logging - -# Your existing logging setup -logger = logging.getLogger(__name__) - -# These logs will be automatically sent to Sentry -logger.info('This will be sent to Sentry') -logger.warning('User login failed') -logger.error('Something went wrong')`, - }, - ], -});