feat(monitoring): integrate sentry with tenant context and gitea actions
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 48s

This commit is contained in:
Cauê Faleiros
2026-02-18 09:55:41 -03:00
parent 4a59246398
commit 79ee93d48c
7 changed files with 664 additions and 435 deletions

View File

@@ -13,6 +13,16 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Create Sentry Release
uses: getsentry/action-release@v1
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
with:
environment: production
version: ${{ gitea.sha }}
- name: Debug Environment - name: Debug Environment
run: | run: |
echo "User: $(whoami)" echo "User: $(whoami)"

402
GEMINI.md
View File

@@ -4,11 +4,11 @@
**Growup Pro** is a whitelabel implementation of [Krayin Laravel CRM](https://github.com/krayin/laravel-crm) with multi-tenancy support. The platform allows multiple companies/organizations to use the same CRM instance with complete data isolation through subdomain-based tenancy. **Growup Pro** is a whitelabel implementation of [Krayin Laravel CRM](https://github.com/krayin/laravel-crm) with multi-tenancy support. The platform allows multiple companies/organizations to use the same CRM instance with complete data isolation through subdomain-based tenancy.
**CURRENT STATUS: DEBUGGING PHASE** **CURRENT STATUS: FEATURE IMPLEMENTATION PHASE**
- **Multi-tenancy implementation**: Installed but encountering issues. - **Multi-tenancy implementation**: Stable.
- **Issue 1**: `localhost` not recognized as central domain (TenantCouldNotBeIdentifiedOnDomainException). - **Authentication**: Stable (Infinite redirect loop resolved).
- **Issue 2**: Tenant instances (`tenant1.localhost`) load but missing CSS (Asset 404). - **Core Systems**: Localhost and central domain detection working.
- **Goal**: Fix central domain detection and static asset serving for tenants. - **Goal**: Implement advanced admin features, Sentry integration, and finalize branding.
### Key Differentiators from Krayin ### Key Differentiators from Krayin
- **Rebranding**: Complete visual overhaul with Growup Pro branding - **Rebranding**: Complete visual overhaul with Growup Pro branding
@@ -326,350 +326,15 @@ Route::post('/register-tenant', [TenantController::class, 'register']);
- `resources/lang/pt_BR/` - Portuguese translations - `resources/lang/pt_BR/` - Portuguese translations
- `resources/views/layouts/app.blade.php` - Main layout (branded) - `resources/views/layouts/app.blade.php` - Main layout (branded)
## CRITICAL: Krayin Authentication Issues (MUST RESOLVE BEFORE MULTI-TENANCY) ## Resolved Issues (History)
**IMPORTANT:** Multi-tenancy implementation is ON HOLD until we stabilize Krayin's base authentication system. We have experienced critical login issues that must be resolved first. ### Authentication Stabilization
Previous critical issues with infinite redirect loops, CSRF token mismatches (419), and session persistence have been resolved. The authentication system is now stable across local, staging, and production environments.
### Known Authentication Problems ### Multi-tenancy Setup
- **Localhost Detection**: Fixed `TenantCouldNotBeIdentifiedOnDomainException`.
#### Problem 1: Error 419 - CSRF Token Mismatch - **Asset Loading**: Fixed 404 errors for tenant static assets.
**Symptoms:** - **Database Isolation**: Successfully implemented per-tenant databases.
- User enters credentials
- Form submission returns 419 error
- Login fails even with correct credentials
**Possible Causes:**
- Session driver misconfiguration (`file` vs `redis` vs `database`)
- Session cookie not being set properly
- Domain/subdomain mismatch in session configuration
- `APP_URL` mismatch with actual access URL
- CSRF token expiration (session timeout too short)
- Reverse proxy stripping session cookies
**Debug Steps:**
```bash
# Check current session driver
grep SESSION_DRIVER .env
# Clear all caches
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
# Check session files (if using file driver)
ls -la storage/framework/sessions/
# Test session configuration
php artisan tinker
>>> session()->put('test', 'value');
>>> session()->get('test'); # Should return 'value'
```
**Potential Fixes:**
1. **Ensure APP_URL matches access URL exactly:**
```env
# If accessing via localhost:8000
APP_URL=http://localhost:8000
# If accessing via IP
APP_URL=http://192.168.1.100:8000
```
2. **Check session configuration** (`config/session.php`):
```php
'domain' => env('SESSION_DOMAIN', null), // Should match your domain
'secure' => env('SESSION_SECURE_COOKIE', false), // false for HTTP, true for HTTPS
'same_site' => 'lax', // Not 'strict' - can cause issues
```
3. **Verify CSRF middleware** is present in `app/Http/Kernel.php`:
```php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class, // THIS IS CRITICAL
// ...
],
];
```
4. **Check CSRF exceptions** (if login route needs to be excluded):
```php
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
// Add routes here ONLY as last resort
];
```
#### Problem 2: Tenant Database Connection Issues
**Symptoms:**
- Login attempt fails silently
- Database connection errors in logs
- Can't authenticate against tenant-specific users table
**Possible Causes:**
- Tenant database doesn't exist yet
- Database migrations not run on tenant database
- Wrong database being queried (central vs tenant)
- Tenant context not initialized before authentication attempt
**Debug Steps:**
```bash
# List all databases
php artisan tinker
>>> DB::select('SHOW DATABASES');
# Check which database Laravel is connected to
>>> DB::connection()->getDatabaseName();
# Verify users table exists in tenant DB
>>> Schema::connection('tenant')->hasTable('users');
```
**Critical Notes for Multi-tenancy:**
- Authentication MUST work in single-tenant (non-multi-tenant) mode FIRST
- Only after stable authentication should we add tenant context switching
- Tenant middleware should NOT interfere with session/CSRF handling
#### Problem 3: Infinite Login Redirect Loop (CRITICAL - UNRESOLVED)
**Symptoms:**
- User enters valid credentials
- Form submits successfully (no 419 error)
- Page redirects back to login page
- User is never authenticated
- Dashboard never loads
- No error messages displayed
**This is the MOST CRITICAL issue and must be debugged thoroughly.**
**Possible Causes:**
1. **Session not persisting after authentication:**
- Session written but immediately destroyed
- Session driver issue (file permissions, Redis connection)
- Session ID regeneration failing
2. **Authentication middleware misconfigured:**
- `Auth` middleware blocking authenticated users
- Wrong guard being checked
- Middleware order issues in Kernel.php
3. **Redirect logic broken:**
- `redirectTo` property in LoginController pointing to login route
- Intended destination not being preserved
- Route name/path mismatch
4. **Auth guard misconfigured:**
- Wrong guard specified in `config/auth.php`
- Provider not finding users correctly
- User model relationship issues
5. **Cookie domain/path mismatch:**
- Session cookie being set but not read back
- Domain attribute too restrictive
- Path attribute incorrect
**Detailed Debug Steps:**
```bash
# 1. Enable query logging to see what's happening
# Add to AppServiceProvider boot():
DB::listen(function ($query) {
Log::info('Query: ' . $query->sql . ' - Bindings: ' . json_encode($query->bindings));
});
# 2. Add extensive logging to login process
# In LoginController or wherever authentication happens:
Log::info('Login attempt for: ' . request()->email);
Log::info('Session ID before auth: ' . session()->getId());
# After Auth::attempt():
Log::info('Auth attempt result: ' . (Auth::check() ? 'success' : 'failed'));
Log::info('Session ID after auth: ' . session()->getId());
Log::info('Authenticated user: ' . (Auth::user() ? Auth::user()->id : 'none'));
# 3. Check session files directly
# If using file driver:
tail -f storage/logs/laravel.log &
# Make login attempt
# Check if session file is created and contains auth data:
cat storage/framework/sessions/*
# 4. Test authentication in Tinker
php artisan tinker
>>> $user = User::first();
>>> Auth::login($user);
>>> Auth::check(); # Should return true
>>> session()->all(); # Check session data
>>> session()->save(); # Manually save session
```
**Configuration Files to Check:**
1. **config/auth.php**
```php
'defaults' => [
'guard' => 'web', // Verify this matches your usage
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class, // Verify model path
],
],
```
2. **config/session.php**
```php
'driver' => env('SESSION_DRIVER', 'file'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
'encrypt' => false,
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION', null),
'table' => 'sessions',
'store' => env('SESSION_STORE', null),
'lottery' => [2, 100],
'cookie' => env('SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session'),
'path' => '/',
'domain' => env('SESSION_DOMAIN', null), // Should be NULL for localhost
'secure' => env('SESSION_SECURE_COOKIE', false), // FALSE for HTTP
'http_only' => true,
'same_site' => 'lax', // NOT 'strict'
```
3. **Verify LoginController redirect logic:**
```php
// Typical Laravel LoginController
protected $redirectTo = '/dashboard'; // NOT '/login'!
// Or method:
protected function redirectTo() {
return '/dashboard'; // Verify this route exists and is accessible
}
// Check authenticated() method isn't causing issues:
protected function authenticated(Request $request, $user) {
// Should NOT return redirect to login
Log::info('User authenticated: ' . $user->id);
}
```
4. **Check middleware in routes:**
```php
// routes/web.php
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
// Verify 'auth' middleware is defined in Kernel.php
// and uses the correct guard
```
**Testing Methodology:**
1. **Isolate the problem:**
```bash
# Create a minimal test route
Route::get('/test-auth', function () {
Auth::login(User::first());
return [
'authenticated' => Auth::check(),
'user_id' => Auth::id(),
'session_id' => session()->getId(),
'session_data' => session()->all(),
];
});
```
2. **Test session persistence separately:**
```bash
Route::get('/test-session-write', function () {
session(['test_key' => 'test_value_' . time()]);
return 'Session written: ' . session('test_key');
});
Route::get('/test-session-read', function () {
return 'Session read: ' . session('test_key', 'NOT FOUND');
});
```
3. **Test authentication without redirect:**
```bash
Route::post('/test-login', function (Request $request) {
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
return [
'status' => 'success',
'user' => Auth::user()->only(['id', 'email']),
'session_id' => session()->getId(),
];
}
return ['status' => 'failed'];
});
```
**Critical Checklist Before Multi-tenancy:**
- [ ] Session driver works correctly (can write and read session data)
- [ ] CSRF protection works (no 419 errors)
- [ ] Auth::attempt() returns true for valid credentials
- [ ] Auth::check() returns true immediately after Auth::attempt()
- [ ] Session persists across requests (test with simple session()->put/get)
- [ ] User can access protected routes after authentication
- [ ] No infinite redirect loops
- [ ] Login process completes in browser devtools Network tab (check for redirect chains)
- [ ] Session cookie is set and sent back with subsequent requests (check devtools Application/Storage)
**DO NOT proceed with multi-tenancy until ALL checklist items pass.**
### Debugging Tools
```bash
# Enable debug mode
APP_DEBUG=true
# Tail logs in real-time
tail -f storage/logs/laravel.log
# Check Redis connection (if using Redis sessions)
redis-cli ping
# Check MySQL connection
php artisan tinker
>>> DB::connection()->getPdo();
# Dump session driver configuration
php artisan tinker
>>> config('session.driver');
>>> config('session.files');
>>> config('session.connection');
# Test file permissions
ls -la storage/framework/sessions/
# Should be writable by web server user
```
### Next Steps After Resolving Authentication
1. Document the exact fix that resolved the issue
2. Create test cases to prevent regression
3. Only then begin multi-tenancy implementation
4. Add monitoring/logging to detect authentication issues early
--- ---
@@ -883,32 +548,28 @@ CLOUDFLARE_ZONE_ID=...
## Admin Dashboard for Tenant Management ## Admin Dashboard for Tenant Management
The platform includes a comprehensive admin dashboard for managing tenants and monitoring platform health. The platform includes a basic admin dashboard for managing tenants.
### Dashboard Features ### Current Implementation (MVP)
- **Route**: `/super-admin` (protected by `super_admin` middleware)
- **Features**:
- Basic Tenant CRUD (Create, Read, Update, Delete)
- Session management (Login/Logout)
- **Tech Stack**: Custom Blade views (`resources/views/super-admin`) + Bootstrap/Tailwind (inherited)
**Tenant Management:** ### Pending Features (Roadmap)
- View all active tenants with key metrics
- Create/edit/delete tenant accounts
- Suspend or activate tenant access
- View tenant resource usage (storage, bandwidth, users)
- Manage tenant subscriptions and billing
**Analytics & Monitoring:** **Analytics & Monitoring:**
- Total active tenants count - Total active tenants count
- Growth metrics (new tenants per month) - Growth metrics (new tenants per month)
- Resource utilization per tenant - Resource utilization per tenant
- Most active tenants (by usage) - Most active tenants (by usage)
- Revenue tracking (if applicable)
- System health overview - System health overview
**Tenant Details View:** **Enhanced Tenant Management:**
- Company information and contact details - View tenant resource usage (storage, bandwidth, users)
- Subdomain and custom domain settings - Manage tenant subscriptions and billing
- User count and activity logs - Suspend or activate tenant access
- Storage usage and database size
- Last login and activity timestamps
- Custom branding settings (logo, colors)
**Bulk Operations:** **Bulk Operations:**
- Bulk tenant creation via CSV import - Bulk tenant creation via CSV import
@@ -923,18 +584,11 @@ The platform includes a comprehensive admin dashboard for managing tenants and m
- Feature flags management - Feature flags management
- Maintenance mode per tenant - Maintenance mode per tenant
### Access Control
- Admin dashboard accessible only to super admins
- Route: `/admin` (protected by `SuperAdmin` middleware)
- Audit logs for all admin actions
- Two-factor authentication required
### Implementation Notes ### Implementation Notes
- Built with Filament Admin Panel (recommended) or custom Blade views - Currently built with custom Blade views.
- Real-time updates using Livewire - **Future Upgrade**: Consider migrating to Filament Admin Panel for richer UI/UX.
- Caching for performance (tenant list, metrics) - **Security**: Route protected by `super_admin` middleware.
- API endpoints for programmatic access - **Audit**: Need to implement audit logs for admin actions.
- Webhooks for tenant lifecycle events (created, suspended, deleted)
## Notes for Gemini AI Assistant ## Notes for Gemini AI Assistant

View File

@@ -3,6 +3,7 @@
namespace App\Exceptions; namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Sentry\Laravel\Integration;
use Throwable; use Throwable;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
@@ -24,7 +25,7 @@ class Handler extends ExceptionHandler
public function register(): void public function register(): void
{ {
$this->reportable(function (Throwable $e) { $this->reportable(function (Throwable $e) {
// Integration::captureUnhandledException($e);
}); });
} }
} }

View File

@@ -4,6 +4,7 @@ namespace App\Providers;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Sentry\State\Scope;
class AppServiceProvider extends ServiceProvider class AppServiceProvider extends ServiceProvider
{ {
@@ -26,6 +27,18 @@ class AppServiceProvider extends ServiceProvider
{ {
Schema::defaultStringLength(191); Schema::defaultStringLength(191);
if (function_exists('tenant')) {
\Sentry\configureScope(function (Scope $scope): void {
if (tenant('id')) {
$scope->setTag('tenant_id', tenant('id'));
$scope->setContext('tenant', [
'id' => tenant('id'),
'data' => tenant()->toArray(),
]);
}
});
}
$this->overrideCoreConfigDefaults(); $this->overrideCoreConfigDefaults();
} }

View File

@@ -23,6 +23,7 @@
"maatwebsite/excel": "^3.1", "maatwebsite/excel": "^3.1",
"mpdf/mpdf": "^8.2", "mpdf/mpdf": "^8.2",
"prettus/l5-repository": "^2.7.9", "prettus/l5-repository": "^2.7.9",
"sentry/sentry-laravel": "*",
"smalot/pdfparser": "^2.11", "smalot/pdfparser": "^2.11",
"stancl/tenancy": "^3.8", "stancl/tenancy": "^3.8",
"webklex/laravel-imap": "^5.3" "webklex/laravel-imap": "^5.3"

535
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "623afca672b2112feb8f9c4a5dc491ce", "content-hash": "0ffcefe86be77a7b4466dd6ccb5158a2",
"packages": [ "packages": [
{ {
"name": "barryvdh/laravel-dompdf", "name": "barryvdh/laravel-dompdf",
@@ -1923,6 +1923,65 @@
], ],
"time": "2025-02-03T10:55:03+00:00" "time": "2025-02-03T10:55:03+00:00"
}, },
{
"name": "jean85/pretty-package-versions",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.1.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Jean85\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alessandro Lai",
"email": "alessandro.lai85@gmail.com"
}
],
"description": "A library to get pretty versions strings of installed dependencies",
"keywords": [
"composer",
"package",
"release",
"versions"
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
},
"time": "2024-11-18T16:19:46+00:00"
},
{ {
"name": "khaled.alshamaa/ar-php", "name": "khaled.alshamaa/ar-php",
"version": "v6.3.4", "version": "v6.3.4",
@@ -4134,6 +4193,84 @@
], ],
"time": "2024-11-21T10:36:35+00:00" "time": "2024-11-21T10:36:35+00:00"
}, },
{
"name": "nyholm/psr7",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/Nyholm/psr7.git",
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
"shasum": ""
},
"require": {
"php": ">=7.2",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0"
},
"provide": {
"php-http/message-factory-implementation": "1.0",
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"http-interop/http-factory-tests": "^0.9",
"php-http/message-factory": "^1.0",
"php-http/psr7-integration-tests": "^1.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"symfony/error-handler": "^4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
}
},
"autoload": {
"psr-4": {
"Nyholm\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com"
},
{
"name": "Martijn van der Ven",
"email": "martijn@vanderven.se"
}
],
"description": "A fast PHP7 implementation of PSR-7",
"homepage": "https://tnyholm.se",
"keywords": [
"psr-17",
"psr-7"
],
"support": {
"issues": "https://github.com/Nyholm/psr7/issues",
"source": "https://github.com/Nyholm/psr7/tree/1.8.2"
},
"funding": [
{
"url": "https://github.com/Zegnat",
"type": "github"
},
{
"url": "https://github.com/nyholm",
"type": "github"
}
],
"time": "2024-09-09T07:06:30+00:00"
},
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v9.99.100", "version": "v9.99.100",
@@ -5395,6 +5532,184 @@
}, },
"time": "2024-10-27T17:38:32+00:00" "time": "2024-10-27T17:38:32+00:00"
}, },
{
"name": "sentry/sentry",
"version": "4.19.1",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php.git",
"reference": "1c21d60bebe67c0122335bd3fe977990435af0a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/1c21d60bebe67c0122335bd3fe977990435af0a3",
"reference": "1c21d60bebe67c0122335bd3fe977990435af0a3",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"guzzlehttp/psr7": "^1.8.4|^2.1.1",
"jean85/pretty-package-versions": "^1.5|^2.0.4",
"php": "^7.2|^8.0",
"psr/log": "^1.0|^2.0|^3.0",
"symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0|^8.0"
},
"conflict": {
"raven/raven": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.4",
"guzzlehttp/promises": "^2.0.3",
"guzzlehttp/psr7": "^1.8.4|^2.1.1",
"monolog/monolog": "^1.6|^2.0|^3.0",
"phpbench/phpbench": "^1.0",
"phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^8.5|^9.6",
"vimeo/psalm": "^4.17"
},
"suggest": {
"monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler."
},
"type": "library",
"autoload": {
"files": [
"src/functions.php"
],
"psr-4": {
"Sentry\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sentry",
"email": "accounts@sentry.io"
}
],
"description": "PHP SDK for Sentry (http://sentry.io)",
"homepage": "http://sentry.io",
"keywords": [
"crash-reporting",
"crash-reports",
"error-handler",
"error-monitoring",
"log",
"logging",
"profiling",
"sentry",
"tracing"
],
"support": {
"issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/4.19.1"
},
"funding": [
{
"url": "https://sentry.io/",
"type": "custom"
},
{
"url": "https://sentry.io/pricing/",
"type": "custom"
}
],
"time": "2025-12-02T15:57:41+00:00"
},
{
"name": "sentry/sentry-laravel",
"version": "4.20.1",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-laravel.git",
"reference": "503853fa7ee74b34b64e76f1373db86cd11afe72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/503853fa7ee74b34b64e76f1373db86cd11afe72",
"reference": "503853fa7ee74b34b64e76f1373db86cd11afe72",
"shasum": ""
},
"require": {
"illuminate/support": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
"nyholm/psr7": "^1.0",
"php": "^7.2 | ^8.0",
"sentry/sentry": "^4.19.0",
"symfony/psr-http-message-bridge": "^1.0 | ^2.0 | ^6.0 | ^7.0 | ^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.11",
"guzzlehttp/guzzle": "^7.2",
"laravel/folio": "^1.1",
"laravel/framework": "^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0 | ^11.0 | ^12.0",
"laravel/pennant": "^1.0",
"livewire/livewire": "^2.0 | ^3.0",
"mockery/mockery": "^1.3",
"orchestra/testbench": "^4.7 | ^5.1 | ^6.0 | ^7.0 | ^8.0 | ^9.0 | ^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^8.4 | ^9.3 | ^10.4 | ^11.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Sentry": "Sentry\\Laravel\\Facade"
},
"providers": [
"Sentry\\Laravel\\ServiceProvider",
"Sentry\\Laravel\\Tracing\\ServiceProvider"
]
}
},
"autoload": {
"psr-0": {
"Sentry\\Laravel\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Sentry",
"email": "accounts@sentry.io"
}
],
"description": "Laravel SDK for Sentry (https://sentry.io)",
"homepage": "https://sentry.io",
"keywords": [
"crash-reporting",
"crash-reports",
"error-handler",
"error-monitoring",
"laravel",
"log",
"logging",
"profiling",
"sentry",
"tracing"
],
"support": {
"issues": "https://github.com/getsentry/sentry-laravel/issues",
"source": "https://github.com/getsentry/sentry-laravel/tree/4.20.1"
},
"funding": [
{
"url": "https://sentry.io/",
"type": "custom"
},
{
"url": "https://sentry.io/pricing/",
"type": "custom"
}
],
"time": "2026-01-07T08:53:19+00:00"
},
{ {
"name": "setasign/fpdi", "name": "setasign/fpdi",
"version": "v2.6.4", "version": "v2.6.4",
@@ -6568,6 +6883,77 @@
], ],
"time": "2025-02-17T21:23:52+00:00" "time": "2025-02-17T21:23:52+00:00"
}, },
{
"name": "symfony/options-resolver",
"version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
"reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
"shasum": ""
},
"require": {
"php": ">=8.4",
"symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\OptionsResolver\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides an improved replacement for the array_replace PHP function",
"homepage": "https://symfony.com",
"keywords": [
"config",
"configuration",
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v8.0.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-11-12T15:55:31+00:00"
},
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.31.0", "version": "v1.31.0",
@@ -7265,6 +7651,94 @@
], ],
"time": "2025-02-04T13:35:48+00:00" "time": "2025-02-04T13:35:48+00:00"
}, },
{
"name": "symfony/psr-http-message-bridge",
"version": "v7.4.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/psr-http-message-bridge.git",
"reference": "929ffe10bbfbb92e711ac3818d416f9daffee067"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/929ffe10bbfbb92e711ac3818d416f9daffee067",
"reference": "929ffe10bbfbb92e711ac3818d416f9daffee067",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/http-message": "^1.0|^2.0",
"symfony/http-foundation": "^6.4|^7.0|^8.0"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-kernel": "<6.4"
},
"require-dev": {
"nyholm/psr7": "^1.1",
"php-http/discovery": "^1.15",
"psr/log": "^1.1.4|^2|^3",
"symfony/browser-kit": "^6.4|^7.0|^8.0",
"symfony/config": "^6.4|^7.0|^8.0",
"symfony/event-dispatcher": "^6.4|^7.0|^8.0",
"symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0",
"symfony/http-kernel": "^6.4.13|^7.1.6|^8.0",
"symfony/runtime": "^6.4.13|^7.1.6|^8.0"
},
"type": "symfony-bridge",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\PsrHttpMessage\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "PSR HTTP message bridge",
"homepage": "https://symfony.com",
"keywords": [
"http",
"http-message",
"psr-17",
"psr-7"
],
"support": {
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.4.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-01-03T23:30:35+00:00"
},
{ {
"name": "symfony/routing", "name": "symfony/routing",
"version": "v6.4.18", "version": "v6.4.18",
@@ -8708,65 +9182,6 @@
}, },
"time": "2020-07-09T08:09:16+00:00" "time": "2020-07-09T08:09:16+00:00"
}, },
{
"name": "jean85/pretty-package-versions",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.1.0",
"php": "^7.4|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Jean85\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alessandro Lai",
"email": "alessandro.lai85@gmail.com"
}
],
"description": "A library to get pretty versions strings of installed dependencies",
"keywords": [
"composer",
"package",
"release",
"versions"
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
},
"time": "2024-11-18T16:19:46+00:00"
},
{ {
"name": "krayin/krayin-package-generator", "name": "krayin/krayin-package-generator",
"version": "dev-master", "version": "dev-master",

135
config/sentry.php Normal file
View File

@@ -0,0 +1,135 @@
<?php
/**
* Sentry Laravel SDK configuration file.
*
* @see https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/
*/
return [
// @see https://docs.sentry.io/product/sentry-basics/dsn-explainer/
'dsn' => env('SENTRY_LARAVEL_DSN', env('SENTRY_DSN')),
// @see https://spotlightjs.com/
// 'spotlight' => env('SENTRY_SPOTLIGHT', false),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#logger
// 'logger' => Sentry\Logger\DebugFileLogger::class, // By default this will log to `storage_path('logs/sentry.log')`
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => env('SENTRY_RELEASE'),
// When left empty or `null` the Laravel environment will be used (usually discovered from `APP_ENV` in your `.env`)
'environment' => env('SENTRY_ENVIRONMENT'),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#sample_rate
'sample_rate' => env('SENTRY_SAMPLE_RATE') === null ? 1.0 : (float) env('SENTRY_SAMPLE_RATE'),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#traces_sample_rate
'traces_sample_rate' => env('SENTRY_TRACES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_TRACES_SAMPLE_RATE'),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#profiles-sample-rate
'profiles_sample_rate' => env('SENTRY_PROFILES_SAMPLE_RATE') === null ? null : (float) env('SENTRY_PROFILES_SAMPLE_RATE'),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#enable_logs
'enable_logs' => env('SENTRY_ENABLE_LOGS', false),
// The minimum log level that will be sent to Sentry as logs using the `sentry_logs` logging channel
'logs_channel_level' => env('SENTRY_LOG_LEVEL', env('SENTRY_LOGS_LEVEL', env('LOG_LEVEL', 'debug'))),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#send_default_pii
'send_default_pii' => env('SENTRY_SEND_DEFAULT_PII', false),
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore_exceptions
// 'ignore_exceptions' => [],
// @see: https://docs.sentry.io/platforms/php/guides/laravel/configuration/options/#ignore_transactions
'ignore_transactions' => [
// Ignore Laravel's default health URL
'/up',
],
// Breadcrumb specific configuration
'breadcrumbs' => [
// Capture Laravel logs as breadcrumbs
'logs' => env('SENTRY_BREADCRUMBS_LOGS_ENABLED', true),
// Capture Laravel cache events (hits, writes etc.) as breadcrumbs
'cache' => env('SENTRY_BREADCRUMBS_CACHE_ENABLED', true),
// Capture Livewire components like routes as breadcrumbs
'livewire' => env('SENTRY_BREADCRUMBS_LIVEWIRE_ENABLED', true),
// Capture SQL queries as breadcrumbs
'sql_queries' => env('SENTRY_BREADCRUMBS_SQL_QUERIES_ENABLED', true),
// Capture SQL query bindings (parameters) in SQL query breadcrumbs
'sql_bindings' => env('SENTRY_BREADCRUMBS_SQL_BINDINGS_ENABLED', false),
// Capture queue job information as breadcrumbs
'queue_info' => env('SENTRY_BREADCRUMBS_QUEUE_INFO_ENABLED', true),
// Capture command information as breadcrumbs
'command_info' => env('SENTRY_BREADCRUMBS_COMMAND_JOBS_ENABLED', true),
// Capture HTTP client request information as breadcrumbs
'http_client_requests' => env('SENTRY_BREADCRUMBS_HTTP_CLIENT_REQUESTS_ENABLED', true),
// Capture send notifications as breadcrumbs
'notifications' => env('SENTRY_BREADCRUMBS_NOTIFICATIONS_ENABLED', true),
],
// Performance monitoring specific configuration
'tracing' => [
// Trace queue jobs as their own transactions (this enables tracing for queue jobs)
'queue_job_transactions' => env('SENTRY_TRACE_QUEUE_ENABLED', true),
// Capture queue jobs as spans when executed on the sync driver
'queue_jobs' => env('SENTRY_TRACE_QUEUE_JOBS_ENABLED', true),
// Capture SQL queries as spans
'sql_queries' => env('SENTRY_TRACE_SQL_QUERIES_ENABLED', true),
// Capture SQL query bindings (parameters) in SQL query spans
'sql_bindings' => env('SENTRY_TRACE_SQL_BINDINGS_ENABLED', false),
// Capture where the SQL query originated from on the SQL query spans
'sql_origin' => env('SENTRY_TRACE_SQL_ORIGIN_ENABLED', true),
// Define a threshold in milliseconds for SQL queries to resolve their origin
'sql_origin_threshold_ms' => env('SENTRY_TRACE_SQL_ORIGIN_THRESHOLD_MS', 100),
// Capture views rendered as spans
'views' => env('SENTRY_TRACE_VIEWS_ENABLED', true),
// Capture Livewire components as spans
'livewire' => env('SENTRY_TRACE_LIVEWIRE_ENABLED', true),
// Capture HTTP client requests as spans
'http_client_requests' => env('SENTRY_TRACE_HTTP_CLIENT_REQUESTS_ENABLED', true),
// Capture Laravel cache events (hits, writes etc.) as spans
'cache' => env('SENTRY_TRACE_CACHE_ENABLED', true),
// Capture Redis operations as spans (this enables Redis events in Laravel)
'redis_commands' => env('SENTRY_TRACE_REDIS_COMMANDS', false),
// Capture where the Redis command originated from on the Redis command spans
'redis_origin' => env('SENTRY_TRACE_REDIS_ORIGIN_ENABLED', true),
// Capture send notifications as spans
'notifications' => env('SENTRY_TRACE_NOTIFICATIONS_ENABLED', true),
// Enable tracing for requests without a matching route (404's)
'missing_routes' => env('SENTRY_TRACE_MISSING_ROUTES_ENABLED', false),
// Configures if the performance trace should continue after the response has been sent to the user until the application terminates
// This is required to capture any spans that are created after the response has been sent like queue jobs dispatched using `dispatch(...)->afterResponse()` for example
'continue_after_response' => env('SENTRY_TRACE_CONTINUE_AFTER_RESPONSE', true),
// Enable the tracing integrations supplied by Sentry (recommended)
'default_integrations' => env('SENTRY_TRACE_DEFAULT_INTEGRATIONS_ENABLED', true),
],
];