Sentry Sentinel Theme
Beautiful web syntax highlighter themes for Prism.js and Highlight.js
Use the dropdowns below to switch between themes and programming languages. Compare how each theme looks in both Prism.js and Highlight.js side by side.
View the project on GitHub
Code Examples
JavaScript
// Sentry error tracking example
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: "https://example@sentry.io/123456",
environment: "production",
integrations: [
new Sentry.BrowserTracing(),
],
tracesSampleRate: 1.0,
});
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
Sentry.captureException(error, {
contexts: { react: { componentStack: errorInfo.componentStack } }
});
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// Sentry error tracking example
import * as Sentry from '@sentry/browser';
Sentry.init({
dsn: "https://example@sentry.io/123456",
environment: "production",
integrations: [
new Sentry.BrowserTracing(),
],
tracesSampleRate: 1.0,
});
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
Sentry.captureException(error, {
contexts: { react: { componentStack: errorInfo.componentStack } }
});
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
TypeScript
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}
type AsyncResult = Promise<{ data: T; error?: never } | { data?: never; error: Error }>;
async function fetchUser(id: string): AsyncResult {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return { data };
} catch (error) {
return { error: error instanceof Error ? error : new Error('Unknown error') };
}
}
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
class UserCache {
private cache = new Map();
get(id: string): User | null {
const cached = this.cache.get(id);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return cached.user;
}
return null;
}
set(id: string, user: User): void {
this.cache.set(id, { user, timestamp: Date.now() });
}
}
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}
type AsyncResult = Promise<{ data: T; error?: never } | { data?: never; error: Error }>;
async function fetchUser(id: string): AsyncResult {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return { data };
} catch (error) {
return { error: error instanceof Error ? error : new Error('Unknown error') };
}
}
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
class UserCache {
private cache = new Map();
get(id: string): User | null {
const cached = this.cache.get(id);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return cached.user;
}
return null;
}
set(id: string, user: User): void {
this.cache.set(id, { user, timestamp: Date.now() });
}
}
Python
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from typing import Optional, Dict, Any
import functools
import time
sentry_sdk.init(
dsn="https://example@sentry.io/123456",
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
send_default_pii=True
)
def performance_monitor(func):
"""Decorator to monitor function performance with Sentry."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
with sentry_sdk.start_transaction(op="function", name=func.__name__) as transaction:
start_time = time.time()
try:
result = func(*args, **kwargs)
transaction.set_status("ok")
return result
except Exception as e:
transaction.set_status("internal_error")
sentry_sdk.capture_exception(e)
raise
finally:
duration = time.time() - start_time
transaction.set_data("duration", duration)
return wrapper
class DataProcessor:
def __init__(self, config: Dict[str, Any]):
self.config = config
self.cache: Dict[str, Any] = {}
@performance_monitor
def process_batch(self, items: list) -> Optional[Dict[str, Any]]:
"""Process a batch of items with error handling."""
results = []
for item in items:
try:
processed = self._process_single(item)
results.append(processed)
except ValueError as e:
sentry_sdk.capture_message(f"Invalid item: {item}", level="warning")
continue
return {"processed": len(results), "failed": len(items) - len(results)}
def _process_single(self, item: Any) -> Any:
"""Process a single item."""
if not isinstance(item, dict):
raise ValueError(f"Expected dict, got {type(item)}")
# Simulate processing
return {**item, "processed": True, "timestamp": time.time()}
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from typing import Optional, Dict, Any
import functools
import time
sentry_sdk.init(
dsn="https://example@sentry.io/123456",
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
send_default_pii=True
)
def performance_monitor(func):
"""Decorator to monitor function performance with Sentry."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
with sentry_sdk.start_transaction(op="function", name=func.__name__) as transaction:
start_time = time.time()
try:
result = func(*args, **kwargs)
transaction.set_status("ok")
return result
except Exception as e:
transaction.set_status("internal_error")
sentry_sdk.capture_exception(e)
raise
finally:
duration = time.time() - start_time
transaction.set_data("duration", duration)
return wrapper
class DataProcessor:
def __init__(self, config: Dict[str, Any]):
self.config = config
self.cache: Dict[str, Any] = {}
@performance_monitor
def process_batch(self, items: list) -> Optional[Dict[str, Any]]:
"""Process a batch of items with error handling."""
results = []
for item in items:
try:
processed = self._process_single(item)
results.append(processed)
except ValueError as e:
sentry_sdk.capture_message(f"Invalid item: {item}", level="warning")
continue
return {"processed": len(results), "failed": len(items) - len(results)}
def _process_single(self, item: Any) -> Any:
"""Process a single item."""
if not isinstance(item, dict):
raise ValueError(f"Expected dict, got {type(item)}")
# Simulate processing
return {**item, "processed": True, "timestamp": time.time()}
React JSX
import React, { useState, useEffect } from 'react';
import { ErrorBoundary } from '@sentry/react';
const UserProfile = ({ userId }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch user');
const data = await response.json();
setUser(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) return <div className="spinner">Loading...</div>;
if (error) return <div className="error">Error: {error}</div>;
return (
<ErrorBoundary fallback={<div>Something went wrong</div>} showDialog>
<div className="user-profile">
<img src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<div className="stats">
<span>Joined: {new Date(user.joinedAt).toLocaleDateString()}</span>
<span>Posts: {user.postCount}</span>
</div>
</div>
</ErrorBoundary>
);
};
export default UserProfile;
import React, { useState, useEffect } from 'react';
import { ErrorBoundary } from '@sentry/react';
const UserProfile = ({ userId }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch user');
const data = await response.json();
setUser(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
if (loading) return <div className="spinner">Loading...</div>;
if (error) return <div className="error">Error: {error}</div>;
return (
<ErrorBoundary fallback={<div>Something went wrong</div>} showDialog>
<div className="user-profile">
<img src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<div className="stats">
<span>Joined: {new Date(user.joinedAt).toLocaleDateString()}</span>
<span>Posts: {user.postCount}</span>
</div>
</div>
</ErrorBoundary>
);
};
export default UserProfile;
CSS
/* Sentry-themed button styles */
.btn-sentry {
--primary: var(--purple-primary);
--primary-hover: var(--purple-tertiary);
--accent: #FF45A8;
display: inline-flex;
align-items: center;
padding: 0.75rem 1.5rem;
font-weight: 500;
font-size: 1rem;
line-height: 1.5;
color: white;
background-color: var(--primary);
border: 2px solid transparent;
border-radius: 8px;
transition: all 0.2s ease-in-out;
cursor: pointer;
text-decoration: none;
}
.btn-sentry:hover {
background-color: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(54, 22, 107, 0.3);
}
.btn-sentry:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(54, 22, 107, 0.2);
}
.btn-sentry--accent {
background-color: var(--accent);
}
.btn-sentry--accent:hover {
background-color: #FF70BC;
}
@media (prefers-reduced-motion: reduce) {
.btn-sentry {
transition: none;
}
}
/* Sentry-themed button styles */
.btn-sentry {
--primary: var(--purple-primary);
--primary-hover: var(--purple-tertiary);
--accent: #FF45A8;
display: inline-flex;
align-items: center;
padding: 0.75rem 1.5rem;
font-weight: 500;
font-size: 1rem;
line-height: 1.5;
color: white;
background-color: var(--primary);
border: 2px solid transparent;
border-radius: 8px;
transition: all 0.2s ease-in-out;
cursor: pointer;
text-decoration: none;
}
.btn-sentry:hover {
background-color: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(54, 22, 107, 0.3);
}
.btn-sentry:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(54, 22, 107, 0.2);
}
.btn-sentry--accent {
background-color: var(--accent);
}
.btn-sentry--accent:hover {
background-color: #FF70BC;
}
@media (prefers-reduced-motion: reduce) {
.btn-sentry {
transition: none;
}
}
JSON
{
"name": "sentry-sentinel-theme",
"version": "1.0.0",
"description": "Official Sentry theme for syntax highlighting",
"author": "Sentry",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/getsentry/sentinel"
},
"keywords": [
"sentry",
"theme",
"syntax-highlighting",
"prism",
"highlight.js"
],
"themes": {
"light": {
"primary": "var(--purple-primary)",
"secondary": "var(--purple-secondary)",
"accent": "#FF45A8"
},
"dark": {
"primary": "#9E86FF",
"secondary": "#FF70BC",
"accent": "#C0ED49"
}
},
"scripts": {
"test": "node test.js",
"build": "node build.js"
}
}
{
"name": "sentry-sentinel-theme",
"version": "1.0.0",
"description": "Official Sentry theme for syntax highlighting",
"author": "Sentry",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/getsentry/sentinel"
},
"keywords": [
"sentry",
"theme",
"syntax-highlighting",
"prism",
"highlight.js"
],
"themes": {
"light": {
"primary": "var(--purple-primary)",
"secondary": "var(--purple-secondary)",
"accent": "#FF45A8"
},
"dark": {
"primary": "#9E86FF",
"secondary": "#FF70BC",
"accent": "#C0ED49"
}
},
"scripts": {
"test": "node test.js",
"build": "node build.js"
}
}
YAML
# Sentry configuration
sentry:
dsn: https://example@sentry.io/123456
environment: production
traces_sample_rate: 1.0
integrations:
- name: BrowserTracing
options:
routingInstrumentation: vue
- name: Replay
options:
maskAllText: false
blockAllMedia: false
app:
name: My Application
version: 1.2.3
features:
- authentication
- real-time-updates
- error-tracking
database:
host: localhost
port: 5432
name: myapp_prod
ssl: true
cache:
provider: redis
ttl: 3600
max_entries: 10000
# Sentry configuration
sentry:
dsn: https://example@sentry.io/123456
environment: production
traces_sample_rate: 1.0
integrations:
- name: BrowserTracing
options:
routingInstrumentation: vue
- name: Replay
options:
maskAllText: false
blockAllMedia: false
app:
name: My Application
version: 1.2.3
features:
- authentication
- real-time-updates
- error-tracking
database:
host: localhost
port: 5432
name: myapp_prod
ssl: true
cache:
provider: redis
ttl: 3600
max_entries: 10000
SQL
-- Get user activity with error tracking
WITH user_errors AS (
SELECT
u.user_id,
u.username,
COUNT(e.error_id) as error_count,
MAX(e.occurred_at) as last_error
FROM users u
LEFT JOIN errors e ON u.user_id = e.user_id
WHERE e.occurred_at >= NOW() - INTERVAL '7 days'
GROUP BY u.user_id, u.username
)
SELECT
ue.*,
COALESCE(s.session_count, 0) as sessions_last_week,
CASE
WHEN ue.error_count > 10 THEN 'high'
WHEN ue.error_count > 5 THEN 'medium'
ELSE 'low'
END as error_severity
FROM user_errors ue
LEFT JOIN (
SELECT user_id, COUNT(*) as session_count
FROM sessions
WHERE created_at >= NOW() - INTERVAL '7 days'
GROUP BY user_id
) s ON ue.user_id = s.user_id
ORDER BY ue.error_count DESC
LIMIT 100;
-- Get user activity with error tracking
WITH user_errors AS (
SELECT
u.user_id,
u.username,
COUNT(e.error_id) as error_count,
MAX(e.occurred_at) as last_error
FROM users u
LEFT JOIN errors e ON u.user_id = e.user_id
WHERE e.occurred_at >= NOW() - INTERVAL '7 days'
GROUP BY u.user_id, u.username
)
SELECT
ue.*,
COALESCE(s.session_count, 0) as sessions_last_week,
CASE
WHEN ue.error_count > 10 THEN 'high'
WHEN ue.error_count > 5 THEN 'medium'
ELSE 'low'
END as error_severity
FROM user_errors ue
LEFT JOIN (
SELECT user_id, COUNT(*) as session_count
FROM sessions
WHERE created_at >= NOW() - INTERVAL '7 days'
GROUP BY user_id
) s ON ue.user_id = s.user_id
ORDER BY ue.error_count DESC
LIMIT 100;
Go
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/getsentry/sentry-go"
)
type ErrorHandler struct {
client *sentry.Client
}
func NewErrorHandler(dsn string) (*ErrorHandler, error) {
client, err := sentry.NewClient(sentry.ClientOptions{
Dsn: dsn,
Environment: "production",
TracesSampleRate: 1.0,
BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
if event.Level == sentry.LevelDebug {
return nil
}
return event
},
})
if err != nil {
return nil, fmt.Errorf("sentry init failed: %w", err)
}
return &ErrorHandler{client: client}, nil
}
func (h *ErrorHandler) HandlePanic() {
if r := recover(); r != nil {
h.client.RecoverWithContext(
context.Background(),
r,
&sentry.EventHint{RecoveredException: r},
)
h.client.Flush(2 * time.Second)
panic(r)
}
}
func processData(data []byte) error {
defer sentry.StartSpan(context.Background(), "processData").Finish()
if len(data) == 0 {
return fmt.Errorf("empty data provided")
}
// Process data here
time.Sleep(100 * time.Millisecond)
return nil
}
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/getsentry/sentry-go"
)
type ErrorHandler struct {
client *sentry.Client
}
func NewErrorHandler(dsn string) (*ErrorHandler, error) {
client, err := sentry.NewClient(sentry.ClientOptions{
Dsn: dsn,
Environment: "production",
TracesSampleRate: 1.0,
BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
if event.Level == sentry.LevelDebug {
return nil
}
return event
},
})
if err != nil {
return nil, fmt.Errorf("sentry init failed: %w", err)
}
return &ErrorHandler{client: client}, nil
}
func (h *ErrorHandler) HandlePanic() {
if r := recover(); r != nil {
h.client.RecoverWithContext(
context.Background(),
r,
&sentry.EventHint{RecoveredException: r},
)
h.client.Flush(2 * time.Second)
panic(r)
}
}
func processData(data []byte) error {
defer sentry.StartSpan(context.Background(), "processData").Finish()
if len(data) == 0 {
return fmt.Errorf("empty data provided")
}
// Process data here
time.Sleep(100 * time.Millisecond)
return nil
}
Rust
use sentry::{ClientOptions, IntoDsn};
use std::error::Error;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Config {
pub dsn: String,
pub environment: String,
pub sample_rate: f32,
}
impl Default for Config {
fn default() -> Self {
Self {
dsn: String::from("https://example@sentry.io/123456"),
environment: String::from("production"),
sample_rate: 1.0,
}
}
}
pub fn init_sentry(config: Config) -> Result> {
let guard = sentry::init((
config.dsn.as_str(),
ClientOptions {
environment: Some(config.environment.into()),
traces_sample_rate: config.sample_rate,
..Default::default()
},
));
Ok(guard)
}
#[tracing::instrument]
pub async fn process_request(id: u64) -> Result> {
let _span = sentry::start_transaction("process_request", "http.server");
// Simulate processing
tokio::time::sleep(Duration::from_millis(100)).await;
if id % 10 == 0 {
return Err("Invalid request ID".into());
}
Ok(format!("Processed request {}", id))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert_eq!(config.environment, "production");
assert_eq!(config.sample_rate, 1.0);
}
}
use sentry::{ClientOptions, IntoDsn};
use std::error::Error;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Config {
pub dsn: String,
pub environment: String,
pub sample_rate: f32,
}
impl Default for Config {
fn default() -> Self {
Self {
dsn: String::from("https://example@sentry.io/123456"),
environment: String::from("production"),
sample_rate: 1.0,
}
}
}
pub fn init_sentry(config: Config) -> Result> {
let guard = sentry::init((
config.dsn.as_str(),
ClientOptions {
environment: Some(config.environment.into()),
traces_sample_rate: config.sample_rate,
..Default::default()
},
));
Ok(guard)
}
#[tracing::instrument]
pub async fn process_request(id: u64) -> Result> {
let _span = sentry::start_transaction("process_request", "http.server");
// Simulate processing
tokio::time::sleep(Duration::from_millis(100)).await;
if id % 10 == 0 {
return Err("Invalid request ID".into());
}
Ok(format!("Processed request {}", id))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert_eq!(config.environment, "production");
assert_eq!(config.sample_rate, 1.0);
}
}