├── CHANGELOG.md ├── LICENCE.md ├── README.md ├── composer.json ├── config └── treblle.php ├── phpstan.neon ├── pint.json └── src ├── DataProviders ├── LaravelRequestDataProvider.php └── LaravelResponseDataProvider.php ├── Exceptions └── TreblleException.php ├── Middlewares └── TreblleMiddleware.php └── TreblleServiceProvider.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [2.8.1] - 2022-02-25 9 | ### Changed 10 | - provide a fallback for masked fields list in case someone updated the package and didn't clear their cache (it happens) 11 | 12 | ## [2.8.0] - 2022-02-25 13 | ### Changed 14 | - using Laravel HTTP client instead of Guzzle 15 | - fixed missing Cache facade 16 | - simplifed the Laravel Octane check 17 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Treblle Limited. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 | # Treblle 7 | 8 | Integrations 9 |   •   10 | Website 11 |   •   12 | Docs 13 |   •   14 | Blog 15 |   •   16 | Twitter 17 |   •   18 | Discord 19 |
20 | 21 |
22 |
23 | 24 | API Intelligence Platform. 🚀 25 | 26 | Treblle is a lightweight SDK that helps Engineering and Product teams build, ship & maintain REST-based APIs faster. 27 | 28 | ## Features 29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 | 37 | - [API Monitoring & Observability](https://www.treblle.com/features/api-monitoring-observability) 38 | - [Auto-generated API Docs](https://www.treblle.com/features/auto-generated-api-docs) 39 | - [API analytics](https://www.treblle.com/features/api-analytics) 40 | - [Treblle API Score](https://www.treblle.com/features/api-quality-score) 41 | - [API Lifecycle Collaboration](https://www.treblle.com/features/api-lifecycle) 42 | - [Native Treblle Apps](https://www.treblle.com/features/native-apps) 43 | 44 | 45 | ## How Treblle Works 46 | Once you’ve integrated a Treblle SDK in your codebase, this SDK will send requests and response data to your Treblle Dashboard. 47 | 48 | In your Treblle Dashboard you get to see real-time requests to your API, auto-generated API docs, API analytics like how fast the response was for an endpoint, the load size of the response, etc. 49 | 50 | Treblle also uses the requests sent to your Dashboard to calculate your API score which is a quality score that’s calculated based on the performance, quality, and security best practices for your API. 51 | 52 | > Visit [https://docs.treblle.com](http://docs.treblle.com) for the complete documentation. 53 | 54 | ## Security 55 | 56 | ### Masking fields 57 | Masking fields ensure certain sensitive data are removed before being sent to Treblle. 58 | 59 | To make sure masking is done before any data leaves your server [we built it into all our SDKs](https://docs.treblle.com/en/security/masked-fields#fields-masked-by-default). 60 | 61 | This means data masking is super fast and happens on a programming level before the API request is sent to Treblle. You can [customize](https://docs.treblle.com/en/security/masked-fields#custom-masked-fields) exactly which fields are masked when you’re integrating the SDK. 62 | 63 | > Visit the [Masked fields](https://docs.treblle.com/en/security/masked-fields) section of the [docs](https://docs.sailscasts.com) for the complete documentation. 64 | 65 | 66 | ## Get Started 67 | 68 | 1. Sign in to [Treblle](https://platform.treblle.com). 69 | 2. [Create a Treblle project](https://docs.treblle.com/en/dashboard/projects#creating-a-project). 70 | 3. [Setup the SDK](#install-the-SDK) for your platform. 71 | 72 | ### Install the SDK 73 | 74 | Install Treblle for Laravel via Composer by running the following command in your terminal: 75 | 76 | ```sh 77 | composer require treblle/treblle-laravel 78 | ``` 79 | 80 | You can get started with Treblle **directly from your Artisan console**. Just type in the following command in your 81 | terminal: 82 | 83 | ```bash 84 | php artisan treblle:start 85 | ``` 86 | 87 | The command guides you through a process and allows you to create an account, login to your existing account, create a 88 | new project and get all the `.ENV` keys you need to start using Treblle. 89 | 90 | You can also visit our website [https://app.treblle.com](https://app.treblle.com) and create a FREE account to get your API key and Project ID. Once 91 | you have them, simply add them to your `.ENV` file: 92 | 93 | ```shell 94 | TREBLLE_API_KEY=YOUR_API_KEY 95 | TREBLLE_PROJECT_ID=YOUR_PROJECT_ID 96 | ``` 97 | ## Enabling Treblle on your API 98 | 99 | Your first step should be to register Treblle into your in your middleware aliases in `app/Http/Kernel.php`: 100 | 101 | ```php 102 | protected $middlewareAliases = [ 103 | // the rest of your middleware aliases 104 | 'treblle' => \Treblle\Laravel\Middlewares\TreblleMiddleware::class, 105 | ]; 106 | ``` 107 | 108 | Open the **routes/api.php** and add the Treblle middleware to either a route group like so: 109 | 110 | ```php 111 | Route::middleware(['treblle'])->group(function () { 112 | 113 | // YOUR API ROUTES GO HERE 114 | Route::prefix('samples')->group(function () { 115 | Route::get('{uuid}', [SampleController::class, 'view']); 116 | Route::post('store', [SampleController::class, 'store']); 117 | }); 118 | 119 | }); 120 | ``` 121 | 122 | or to an individual route like so: 123 | 124 | ```php 125 | Route::group(function () { 126 | Route::prefix('users')->group(function () { 127 | 128 | // IS LOGGED BY TREBLLE 129 | Route::get('{uuid}', [UserController::class, 'view'])->middleware('treblle'); 130 | 131 | // IS NOT LOGGED BY TREBLLE 132 | Route::post('{uuid}/update', [UserController::class, 'update']); 133 | }); 134 | }); 135 | ``` 136 | or if you have multiple projects within same workspace in same laravel project you can set project ids dynamically like so: 137 | 138 | NOTE: Dynamically set value will always take precedence over value set in .env 139 | 140 | ```php 141 | Route::middleware(['treblle:project-id-1'])->group(function () { 142 | 143 | // YOUR API ROUTES GO HERE 144 | Route::prefix('samples')->group(function () { 145 | Route::get('{uuid}', [SampleController::class, 'view']); 146 | Route::post('store', [SampleController::class, 'store']); 147 | }); 148 | 149 | }); 150 | 151 | Route::middleware(['treblle:project-id-2'])->group(function () { 152 | 153 | // YOUR API ROUTES GO HERE 154 | Route::prefix('samples')->group(function () { 155 | Route::get('{uuid}', [AnotherSampleController::class, 'view']); 156 | Route::post('store', [AnotherSampleController::class, 'store']); 157 | }); 158 | 159 | }); 160 | ``` 161 | 162 | NOTE: In case you want to temporarily disable observability, you can do so by setting env as `TREBLLE_ENABLE=false` 163 | 164 | You're all set. Next time someone makes a request to your API you will see it in real-time on your Treblle dashboard 165 | alongside other features like: auto-generated documentation, error tracking, analytics and API quality scoring. 166 | 167 | > See the [docs](https://docs.treblle.com/en/integrations/laravel) for this SDK to learn more. 168 | 169 | ## Available SDKs 170 | 171 | Treblle provides [open-source SDKs](https://docs.treblle.com/en/integrations) that let you seamlessly integrate Treblle with your REST-based APIs. 172 | 173 | - [`treblle-laravel`](https://github.com/Treblle/treblle-laravel): SDK for Laravel 174 | - [`treblle-php`](https://github.com/Treblle/treblle-php): SDK for PHP 175 | - [`treblle-symfony`](https://github.com/Treblle/treblle-symfony): SDK for Symfony 176 | - [`treblle-lumen`](https://github.com/Treblle/treblle-lumen): SDK for Lumen 177 | - [`treblle-sails`](https://github.com/Treblle/treblle-sails): SDK for Sails 178 | - [`treblle-adonisjs`](https://github.com/Treblle/treblle-adonisjs): SDK for AdonisJS 179 | - [`treblle-fastify`](https://github.com/Treblle/treblle-fastify): SDK for Fastify 180 | - [`treblle-directus`](https://github.com/Treblle/treblle-directus): SDK for Directus 181 | - [`treblle-strapi`](https://github.com/Treblle/treblle-strapi): SDK for Strapi 182 | - [`treblle-express`](https://github.com/Treblle/treblle-express): SDK for Express 183 | - [`treblle-koa`](https://github.com/Treblle/treblle-koa): SDK for Koa 184 | - [`treblle-go`](https://github.com/Treblle/treblle-go): SDK for Go 185 | - [`treblle-ruby`](https://github.com/Treblle/treblle-ruby): SDK for Ruby on Rails 186 | - [`treblle-python`](https://github.com/Treblle/treblle-python): SDK for Python/Django 187 | 188 | > See the [docs](https://docs.treblle.com/en/integrations) for more on SDKs and Integrations. 189 | 190 | ## Other Packages 191 | 192 | Besides the SDKs, we also provide helpers and configuration used for SDK 193 | development. If you're thinking about contributing to or creating a SDK, have a look at the resources 194 | below: 195 | 196 | - [`treblle-utils`](https://github.com/Treblle/treblle-utils): A set of helpers and 197 | utility functions useful for the JavaScript SDKs. 198 | - [`php-utils`](https://github.com/Treblle/php-utils): A set of helpers and 199 | utility functions useful for the PHP SDKs. 200 | 201 | ## Community 💙 202 | 203 | First and foremost: **Star and watch this repository** to stay up-to-date. 204 | 205 | Also, follow our [Blog](https://blog.treblle.com), and on [Twitter](https://twitter.com/treblleapi). 206 | 207 | You can chat with the team and other members on [Discord](https://treblle.com/chat) and follow our tutorials and other video material at [YouTube](https://youtube.com/@treblle). 208 | 209 | [![Treblle Discord](https://img.shields.io/badge/Treblle%20Discord-Join%20our%20Discord-F3F5FC?labelColor=7289DA&style=for-the-badge&logo=discord&logoColor=F3F5FC&link=https://treblle.com/chat)](https://treblle.com/chat) 210 | 211 | [![Treblle YouTube](https://img.shields.io/badge/Treblle%20YouTube-Subscribe%20on%20YouTube-F3F5FC?labelColor=c4302b&style=for-the-badge&logo=YouTube&logoColor=F3F5FC&link=https://youtube.com/@treblle)](https://youtube.com/@treblle) 212 | 213 | [![Treblle on Twitter](https://img.shields.io/badge/Treblle%20on%20Twitter-Follow%20Us-F3F5FC?labelColor=1DA1F2&style=for-the-badge&logo=Twitter&logoColor=F3F5FC&link=https://twitter.com/treblleapi)](https://twitter.com/treblleapi) 214 | 215 | ### How to contribute 216 | 217 | Here are some ways of contributing to making Treblle better: 218 | 219 | - **[Try out Treblle](https://docs.treblle.com/en/introduction#getting-started)**, and let us know ways to make Treblle better for you. Let us know here on [Discord](https://treblle.com/chat). 220 | - Join our [Discord](https://treblle.com/chat) and connect with other members to share and learn from. 221 | - Send a pull request to any of our [open source repositories](https://github.com/Treblle) on Github. Check the contribution guide on the repo you want to contribute to for more details about how to contribute. We're looking forward to your contribution! 222 | 223 | ### Contributors 224 | 225 |

226 | A table of avatars from the project's contributors 227 |

228 |
229 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "treblle/treblle-laravel", 3 | "description": "Stay in tune with your APIs", 4 | "license": "MIT", 5 | "homepage": "https://treblle.com/", 6 | "type": "library", 7 | "keywords": [ 8 | "api", 9 | "debuging", 10 | "documentation", 11 | "laravel", 12 | "monitoring", 13 | "treblle" 14 | ], 15 | "authors": [ 16 | { 17 | "role": "Developer", 18 | "name": "Vedran Cindrić", 19 | "email": "vedran@treblle.com", 20 | "homepage": "https://treblle.com/" 21 | } 22 | ], 23 | "autoload": { 24 | "psr-4": { 25 | "Treblle\\Laravel\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "Treblle\\Laravel\\Tests\\": "tests/" 31 | } 32 | }, 33 | "require": { 34 | "php": "^8.2", 35 | "ext-json": "*", 36 | "ext-mbstring": "*", 37 | "treblle/treblle-php": "^4.0.2" 38 | }, 39 | "require-dev": { 40 | "orchestra/testbench": "^7.0 || ^8.5.9", 41 | "laravel/pint": "^1.15" 42 | }, 43 | "extra": { 44 | "laravel": { 45 | "providers": [ 46 | "Treblle\\Laravel\\TreblleServiceProvider" 47 | ] 48 | } 49 | }, 50 | "scripts": { 51 | "pint": [ 52 | "./vendor/bin/pint" 53 | ], 54 | "stan": [ 55 | "./vendor/bin/phpstan analyse" 56 | ], 57 | "test": [ 58 | "./vendor/bin/phpunit" 59 | ] 60 | }, 61 | "minimum-stability": "stable", 62 | "prefer-stable": true, 63 | "config": { 64 | "preferred-install": "dist", 65 | "sort-packages": true, 66 | "allow-plugins": { 67 | "php-http/discovery": true, 68 | "pestphp/pest-plugin": true 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /config/treblle.php: -------------------------------------------------------------------------------- 1 | env('TREBLLE_ENABLE', true), 10 | 11 | /* 12 | * An override while debugging. 13 | */ 14 | 'url' => null, 15 | 16 | /* 17 | * A valid Treblle API key. You can get started for FREE by visiting https://treblle.com/ 18 | */ 19 | 'api_key' => env('TREBLLE_API_KEY'), 20 | 21 | /* 22 | * A valid Treblle project ID. Create your first project on https://treblle.com/ 23 | */ 24 | 'project_id' => env('TREBLLE_PROJECT_ID'), 25 | 26 | /* 27 | * Define which environments should Treblle ignore and not monitor 28 | */ 29 | 'ignored_environments' => env('TREBLLE_IGNORED_ENV', 'dev,test,testing'), 30 | 31 | /* 32 | * Define which fields should be masked before leaving the server 33 | */ 34 | 'masked_fields' => [ 35 | 'password', 36 | 'pwd', 37 | 'secret', 38 | 'password_confirmation', 39 | 'cc', 40 | 'card_number', 41 | 'ccv', 42 | 'ssn', 43 | 'credit_score', 44 | 'api_key', 45 | ], 46 | 47 | /* 48 | * Should be used in development mode only. 49 | * Enable Debug mode, will throw errors on apis. 50 | */ 51 | 'debug' => env('TREBLLE_DEBUG_MODE', false), 52 | ]; 53 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | 3 | paths: 4 | - src/ 5 | 6 | level: 9 7 | 8 | ignoreErrors: 9 | 10 | excludePaths: 11 | 12 | checkMissingIterableValueType: false 13 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "psr12", 3 | "rules": { 4 | "align_multiline_comment": true, 5 | "array_indentation": true, 6 | "array_syntax": true, 7 | "blank_line_between_import_groups": false, 8 | "blank_lines_before_namespace": true, 9 | "blank_line_before_statement": true, 10 | "blank_line_after_namespace": true, 11 | "blank_line_after_opening_tag": true, 12 | "no_extra_blank_lines": true, 13 | "combine_consecutive_issets": true, 14 | "combine_consecutive_unsets": true, 15 | "single_import_per_statement": true, 16 | "single_blank_line_at_eof": true, 17 | "final_public_method_for_abstract_class": false, 18 | "no_trailing_whitespace": true, 19 | "concat_space": { 20 | "spacing": "one" 21 | }, 22 | "final_class": true, 23 | "declare_parentheses": true, 24 | "declare_strict_types": true, 25 | "explicit_string_variable": true, 26 | "fully_qualified_strict_types": true, 27 | "global_namespace_import": { 28 | "import_classes": true, 29 | "import_constants": true, 30 | "import_functions": true 31 | }, 32 | "is_null": true, 33 | "no_unused_imports": true, 34 | "lambda_not_used_import": true, 35 | "logical_operators": true, 36 | "mb_str_functions": true, 37 | "method_chaining_indentation": true, 38 | "modernize_strpos": true, 39 | "trailing_comma_in_multiline": true, 40 | "new_with_braces": true, 41 | "no_empty_comment": true, 42 | "not_operator_with_successor_space": true, 43 | "ordered_traits": true, 44 | "protected_to_private": false, 45 | "simplified_if_return": true, 46 | "strict_comparison": true, 47 | "ternary_to_null_coalescing": true, 48 | "trim_array_spaces": true, 49 | "use_arrow_functions": true, 50 | "void_return": true, 51 | "yoda_style": true, 52 | "array_push": true, 53 | "assign_null_coalescing_to_coalesce_equal": true, 54 | "explicit_indirect_variable": true, 55 | "method_argument_space": { 56 | "on_multiline": "ensure_fully_multiline" 57 | }, 58 | "modernize_types_casting": true, 59 | "no_superfluous_elseif": true, 60 | "no_useless_else": true, 61 | "nullable_type_declaration_for_default_null_value": true, 62 | "ordered_imports": { 63 | "sort_algorithm": "length" 64 | }, 65 | "ordered_class_elements": { 66 | "order": [ 67 | "use_trait", 68 | "case", 69 | "constant", 70 | "constant_public", 71 | "constant_protected", 72 | "constant_private", 73 | "property_public", 74 | "property_protected", 75 | "property_private", 76 | "construct", 77 | "destruct", 78 | "magic", 79 | "phpunit", 80 | "method_abstract", 81 | "method_public_static", 82 | "method_public", 83 | "method_protected_static", 84 | "method_protected", 85 | "method_private_static", 86 | "method_private" 87 | ], 88 | "sort_algorithm": "none" 89 | }, 90 | "class_attributes_separation": { 91 | "elements": { 92 | "const": "none", 93 | "method": "one", 94 | "property": "one", 95 | "trait_import": "none", 96 | "case": "none" 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/DataProviders/LaravelRequestDataProvider.php: -------------------------------------------------------------------------------- 1 | format('Y-m-d H:i:s'), 25 | url: $this->request->fullUrl(), 26 | ip: $this->request->ip() ?? 'bogon', 27 | user_agent: $this->request->userAgent() ?? '', 28 | method: $this->request->method(), 29 | headers: $this->fieldMasker->mask( 30 | collect($this->request->headers->all())->transform( 31 | fn ($item) => collect($item)->first(), 32 | )->toArray() 33 | ), 34 | query: $this->fieldMasker->mask($this->request->query->all()), 35 | body: $this->fieldMasker->mask($this->request->toArray()), 36 | route_path: $this->request->route()?->toSymfonyRoute()->getPath(), 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/DataProviders/LaravelResponseDataProvider.php: -------------------------------------------------------------------------------- 1 | response->getContent(); 29 | $size = mb_strlen($body); 30 | 31 | if ($size > 2 * 1024 * 1024) { 32 | $body = '{}'; 33 | $size = 0; 34 | 35 | $this->errorDataProvider->addError(new Error( 36 | message: 'JSON response size is over 2MB', 37 | file: '', 38 | line: 0, 39 | type: 'E_USER_ERROR' 40 | )); 41 | } 42 | 43 | return new Response( 44 | code: $this->response->getStatusCode(), 45 | size: $size, 46 | load_time: $this->getLoadTimeInMilliseconds(), 47 | body: $this->fieldMasker->mask( 48 | json_decode($body, true) ?? [] 49 | ), 50 | headers: $this->fieldMasker->mask( 51 | collect($this->response->headers->all())->transform( 52 | fn ($item) => collect($item)->first(), 53 | )->toArray() 54 | ), 55 | ); 56 | } 57 | 58 | private function getLoadTimeInMilliseconds(): float 59 | { 60 | $currentTimeInMilliseconds = microtime(true) * 1000; 61 | $requestTimeInMilliseconds = microtime(true) * 1000; 62 | 63 | if ($this->request->attributes->has('treblle_request_started_at')) { 64 | $requestTimeInMilliseconds = $this->request->attributes->get('treblle_request_started_at') * 1000; 65 | 66 | return $currentTimeInMilliseconds - $requestTimeInMilliseconds; 67 | } 68 | 69 | if (isset($_SERVER['REQUEST_TIME_FLOAT'])) { 70 | $requestTimeInMilliseconds = (float)$_SERVER['REQUEST_TIME_FLOAT'] * 1000; 71 | } elseif (defined('LARAVEL_START')) { 72 | $requestTimeInMilliseconds = LARAVEL_START * 1000; 73 | } 74 | 75 | return $currentTimeInMilliseconds - $requestTimeInMilliseconds; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Exceptions/TreblleException.php: -------------------------------------------------------------------------------- 1 | environment(), $ignoredEnvironments)) { 35 | return $next($request); 36 | } 37 | 38 | if (null !== $projectId) { 39 | config(['treblle.project_id' => $projectId]); 40 | } 41 | 42 | if (! (config('treblle.api_key'))) { 43 | throw TreblleException::missingApiKey(); 44 | } 45 | 46 | if (! (config('treblle.project_id'))) { 47 | throw TreblleException::missingProjectId(); 48 | } 49 | 50 | return $next($request); 51 | } 52 | 53 | public function terminate(Request $request, JsonResponse|Response|SymfonyResponse $response): void 54 | { 55 | $ignoredEnvironments = array_map('trim', explode(',', config('treblle.ignored_environments', '') ?? '')); 56 | 57 | if (in_array(app()->environment(), $ignoredEnvironments)) { 58 | return; 59 | } 60 | 61 | $maskedFields = (array)config('treblle.masked_fields'); 62 | $fieldMasker = new FieldMasker($maskedFields); 63 | $errorProvider = new InMemoryErrorDataProvider(); 64 | $requestProvider = new LaravelRequestDataProvider($fieldMasker, $request); 65 | $responseProvider = new LaravelResponseDataProvider($fieldMasker, $request, $response, $errorProvider); 66 | 67 | if (! empty($response->exception)) { 68 | $errorProvider->addError(new Error( 69 | $response->exception->getMessage(), 70 | $response->exception->getFile(), 71 | $response->exception->getLine(), 72 | 'onException', 73 | 'UNHANDLED_EXCEPTION', 74 | )); 75 | } 76 | 77 | $treblle = TreblleFactory::create( 78 | apiKey: (string)config('treblle.api_key'), 79 | projectId: (string)config('treblle.project_id'), 80 | debug: (bool)config('treblle.debug'), 81 | maskedFields: $maskedFields, 82 | config: [ 83 | 'url' => config('treblle.url'), 84 | 'register_handlers' => false, 85 | 'fork_process' => false, 86 | 'request_provider' => $requestProvider, 87 | 'response_provider' => $responseProvider, 88 | 'error_provider' => $errorProvider, 89 | ] 90 | ); 91 | 92 | // Manually execute onShutdown because on octane server never shuts down 93 | // so registered shutdown function never gets called 94 | // hence we have disabled handlers using config register_handlers 95 | $treblle 96 | ->setName(TreblleServiceProvider::SDK_NAME) 97 | ->setVersion(TreblleServiceProvider::SDK_VERSION) 98 | ->onShutdown(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/TreblleServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 26 | $this->publishes([ 27 | __DIR__ . '/../config/treblle.php' => config_path('treblle.php'), 28 | ], 'treblle-config'); 29 | } 30 | 31 | /** @var Router $router */ 32 | $router = $this->app->make(Router::class); 33 | 34 | if (! isset($router->getMiddleware()['treblle'])) { 35 | $router->aliasMiddleware('treblle', TreblleMiddleware::class); 36 | } 37 | 38 | /** @var Dispatcher $events */ 39 | $events = $this->app->make(Dispatcher::class); 40 | 41 | $events->listen('Laravel\Octane\Events\RequestReceived', function ($event): void { 42 | $event->request->attributes->set('treblle_request_started_at', microtime(true)); 43 | }); 44 | 45 | AboutCommand::add( 46 | section: 'Treblle', 47 | data: static fn (): array => [ 48 | 'Version' => self::SDK_VERSION, 49 | 'URL' => config('treblle.url'), 50 | 'Project ID' => config('treblle.project_id'), 51 | 'API Key' => config('treblle.api_key'), 52 | 'Ignored Environments' => config('treblle.ignored_environments'), 53 | ], 54 | ); 55 | } 56 | 57 | /** 58 | * Register the service provider. 59 | */ 60 | public function register(): void 61 | { 62 | $this->mergeConfigFrom( 63 | path: __DIR__ . '/../config/treblle.php', 64 | key: 'treblle', 65 | ); 66 | } 67 | } 68 | --------------------------------------------------------------------------------