File manager - Edit - /home/u816558632/domains/postills.com/public_html/public/arcanedev.tar
Back
log-viewer/composer.json 0000644 00000003275 15002151620 0011345 0 ustar 00 { "name": "arcanedev/log-viewer", "description": "Provides a Log Viewer for Laravel", "keywords": ["arcanedev", "arcanesoft", "laravel", "log", "log viewer", "log-viewer", "logviewer"], "homepage": "https://github.com/ARCANEDEV/LogViewer", "authors": [ { "name": "ARCANEDEV", "email": "arcanedev.maroc@gmail.com", "homepage": "https://github.com/arcanedev-maroc", "role": "Developer" } ], "type": "library", "license": "MIT", "require": { "php": "^8.0", "ext-json": "*", "arcanedev/support": "^9.0", "psr/log": "^1.0|^2.0|^3.0" }, "require-dev": { "laravel/framework": "^9.0", "mockery/mockery": "^1.4.4", "orchestra/testbench-core": "^7.0", "phpunit/phpunit": "^9.5.10" }, "autoload": { "psr-4": { "Arcanedev\\LogViewer\\": "src/" }, "files": ["helpers.php"] }, "autoload-dev": { "psr-4": { "Arcanedev\\LogViewer\\Tests\\": "tests/" } }, "scripts": { "test": "phpunit --colors=always", "test:dox": "phpunit --testdox --colors=always", "test:cov": "phpunit --coverage-html coverage" }, "extra": { "branch-alias": { "dev-develop": "10.x-dev" }, "laravel": { "providers": [ "Arcanedev\\LogViewer\\LogViewerServiceProvider", "Arcanedev\\LogViewer\\Providers\\DeferredServicesProvider" ] } }, "config": { "sort-packages": true }, "minimum-stability": "dev", "prefer-stable": true } log-viewer/translations/zh.json 0000644 00000000450 15002151620 0012650 0 ustar 00 { "Date": "日期", "The list of logs is empty!": "日志列表为空!", "All": "全部", "Emergency": "危急", "Alert": "紧急", "Critical": "严重", "Error": "错误", "Warning": "警告", "Notice": "注意", "Info": "信息", "Debug": "调试" } log-viewer/translations/fa.json 0000644 00000000546 15002151620 0012623 0 ustar 00 { "Date": "تاریخ", "The list of logs is empty!": "لیست لاگ ها خالی است!", "All": "همه", "Emergency": "اورژانسی", "Alert": "اخطار", "Critical": "بحرانی", "Error": "خطا", "Warning": "هشدار", "Notice": "اعلان", "Info": "اطلاعات", "Debug": "دیباگ" } log-viewer/translations/ko.json 0000644 00000000457 15002151620 0012647 0 ustar 00 { "Date": "날짜", "The list of logs is empty!": "로그가 없습니다.", "All": "전체", "Emergency": "긴급", "Alert": "경고", "Critical": "심각", "Error": "오류", "Warning": "주의", "Notice": "알림", "Info": "정보", "Debug": "디버그" } log-viewer/translations/fr.json 0000644 00000000464 15002151620 0012643 0 ustar 00 { "Date": "Date", "The list of logs is empty!": "La liste des logs est vide !", "All": "Tous", "Emergency": "Urgence", "Alert": "Alerte", "Critical": "Critique", "Error": "Erreur", "Warning": "Avertissement", "Notice": "Notice", "Info": "Info", "Debug": "Debug" } log-viewer/translations/uk.json 0000644 00000000654 15002151620 0012654 0 ustar 00 { "Date": "Дата", "The list of logs is empty!": "Список журналів порожній!", "All": "Всі", "Emergency": "Аварійна", "Alert": "Попередження", "Critical": "Критична", "Error": "Помилка", "Warning": "Попереждення", "Notice": "Сповіщення", "Info": "Інформація", "Debug": "Відладка" } log-viewer/translations/ms.json 0000644 00000000450 15002151620 0012646 0 ustar 00 { "Date": "Tarikh", "The list of logs is empty!": "Senarai log kosong!", "All": "Semua", "Emergency": "Kecemasan", "Alert": "Waspada", "Critical": "Kritikal", "Error": "Ralat", "Warning": "Amaran", "Notice": "Notis", "Info": "Info", "Debug": "Debug" } log-viewer/translations/sv.json 0000644 00000000470 15002151620 0012661 0 ustar 00 { "Date": "Datum", "The list of logs is empty!": "Det finns inga loggar att visa.", "All": "Alla", "Emergency": "Akut", "Alert": "Alarmerande", "Critical": "Kritisk", "Error": "Error", "Warning": "Varning", "Notice": "Notis", "Info": "Information", "Debug": "Debug" } log-viewer/translations/zh-TW.json 0000644 00000000463 15002151620 0013204 0 ustar 00 { "Date": "日期", "The list of logs is empty!": "列表中沒有任何紀錄!", "All": "全部", "Emergency": "緊急", "Alert": "警報", "Critical": "嚴重", "Error": "錯誤", "Warning": "警告", "Notice": "注意", "Info": "訊息", "Debug": "除錯" } log-viewer/translations/ar.json 0000644 00000000565 15002151620 0012640 0 ustar 00 { "Date": "تاريخ", "The list of logs is empty!": "قائمة سجلات فارغة!", "All": "الجميع", "Emergency": "حالات الطوارئ", "Alert": "إنذار", "Critical": "حرج", "Error": "خطأ", "Warning": "تحذير", "Notice": "ملاحظة", "Info": "المعلومات", "Debug": "التصحيح" } log-viewer/translations/hy.json 0000644 00000000712 15002151620 0012650 0 ustar 00 { "Date": "Ամսաթիվ", "The list of logs is empty!": "Լոգերի ցուցակը դատարկ է։", "All": "Բոլորը", "Emergency": "Վթարային", "Alert": "Նախազգուշացում", "Critical": "Կրիտիկական", "Error": "Սխալ", "Warning": "Նախազգուշացում", "Notice": "Ծանուցում", "Info": "Տեղեկատվություն", "Debug": "Կարգաբերում" } log-viewer/translations/he.json 0000644 00000000526 15002151620 0012627 0 ustar 00 { "Date": "תאריך", "The list of logs is empty!": "רשימת הלוגים ריקה!", "All": "הכל", "Emergency": "חרום", "Alert": "אזעקה", "Critical": "קריטי", "Error": "שגיאה", "Warning": "אזהרה", "Notice": "הודעה", "Info": "מידע", "Debug": "ניפוי" } log-viewer/translations/nl.json 0000644 00000000473 15002151620 0012645 0 ustar 00 { "Date": "Datum", "The list of logs is empty!": "De lijst met logs is leeg!", "All": "Alle", "Emergency": "Noodgeval", "Alert": "Alarm", "Critical": "Cruciaal", "Error": "Error", "Warning": "Waarschuwing", "Notice": "Opmerking", "Info": "Informatie", "Debug": "Debug" } log-viewer/translations/es.json 0000644 00000000471 15002151620 0012641 0 ustar 00 { "Date": "Fecha", "The list of logs is empty!": "La lista del log está vacía!", "All": "Todos", "Emergency": "Emergencia", "Alert": "Alerta", "Critical": "Criticos", "Error": "Errores", "Warning": "Advertencia", "Notice": "Aviso", "Info": "Info", "Debug": "Debug" } log-viewer/translations/ru.json 0000644 00000000662 15002151620 0012662 0 ustar 00 { "Date": "Дата", "The list of logs is empty!": "Список журналов пуст!", "All": "Все", "Emergency": "Аварийная", "Alert": "Предупреждение", "Critical": "Критический", "Error": "Ошибка", "Warning": "Предупреждение", "Notice": "Уведомление", "Info": "Информация", "Debug": "Отладка" } log-viewer/translations/ro.json 0000644 00000000470 15002151620 0012651 0 ustar 00 { "Date": "Dată", "The list of logs is empty!": "Nu există niciun log!", "All": "Toate", "Emergency": "Urgență", "Alert": "Alertă", "Critical": "Critic", "Error": "Eroare", "Warning": "Pericol", "Notice": "Avertisment", "Info": "Informare", "Debug": "Depanare" } log-viewer/translations/pt-BR.json 0000644 00000000471 15002151620 0013156 0 ustar 00 { "Date": "Data", "The list of logs is empty!": "A lista de logs está vazia!", "All": "Todos", "Emergency": "Emergência", "Alert": "Alerta", "Critical": "Crítico", "Error": "Erro", "Warning": "Aviso", "Notice": "Notícia", "Info": "Informação", "Debug": "Debug" } log-viewer/translations/si.json 0000644 00000000735 15002151620 0012650 0 ustar 00 { "Date": "දිනය", "The list of logs is empty!": "සටහන් ලැයිස්තුව හිස්ය", "All": "සියල්ල", "Emergency": "හදිසි", "Alert": "පරීක්ෂාකාරී", "Critical": "අවදානම්", "Error": "දෝෂය", "Warning": "අවවාදය", "Notice": "නිවේදනය", "Info": "තොරතුරු", "Debug": "නිදොස්කරණය" } log-viewer/translations/hu.json 0000644 00000000523 15002151620 0012644 0 ustar 00 { "Date": "Dátum", "The list of logs is empty!": "A naplók listája üres!", "All": "Összes", "Emergency": "Vészhelyzet", "Alert": "Riasztás", "Critical": "Kritikus", "Error": "Hiba", "Warning": "Figyelmeztetés", "Notice": "Értesítés", "Info": "Információ", "Debug": "Hibakeresés" } log-viewer/translations/bg.json 0000644 00000000506 15002151620 0012621 0 ustar 00 { "Date": "Дата", "The list of logs is empty!": "Не са намерени логове!", "All": "Всички", "Emergency": "Emergency", "Alert": "Alert", "Critical": "Critical", "Error": "Error", "Warning": "Warning", "Notice": "Notice", "Info": "Info", "Debug": "Debug" } log-viewer/translations/tr.json 0000644 00000000456 15002151620 0012662 0 ustar 00 { "Date": "Tarih", "The list of logs is empty!": "Günlük listesi boş!", "All": "Tümü", "Emergency": "Acil", "Alert": "Alarm", "Critical": "Kritik", "Error": "Hata", "Warning": "Uyarı", "Notice": "Bildirim", "Info": "Bilgi", "Debug": "Hata ayıklama" } log-viewer/translations/it.json 0000644 00000000460 15002151620 0012644 0 ustar 00 { "Date": "Data", "The list of logs is empty!": "L'elenco dei log è vuoto!", "All": "Tutti", "Emergency": "Emergenza", "Alert": "Allarme", "Critical": "Critico", "Error": "Errore", "Warning": "Avviso", "Notice": "Notifica", "Info": "Info", "Debug": "Debug" } log-viewer/translations/de.json 0000644 00000000453 15002151620 0012622 0 ustar 00 { "Date": "Datum", "The list of logs is empty!": "KeineLogDateiengefunden!", "All": "Alle", "Emergency": "Notfall", "Alert": "Alarm", "Critical": "Kritisch", "Error": "Fehler", "Warning": "Warnung", "Notice": "Hinweis", "Info": "Info", "Debug": "Debug" } log-viewer/translations/th.json 0000644 00000000720 15002151620 0012642 0 ustar 00 { "Date": "วันที่", "The list of logs is empty!": "ไม่มีรายการล็อก!", "All": "ทั้งหมด", "Emergency": "ฉุกเฉิน", "Alert": "วิกฤติ", "Critical": "ร้ายแรง", "Error": "ข้อผิดพลาด", "Warning": "คำเตือน", "Notice": "ประกาศ", "Info": "ข้อมูล", "Debug": "ดีบัก" } log-viewer/translations/et.json 0000644 00000000467 15002151620 0012647 0 ustar 00 { "Date": "Kuupäev", "The list of logs is empty!": "Logide nimekiri on tühi!", "All": "Kõik", "Emergency": "Erakorraline", "Alert": "Häire", "Critical": "Kriitiline", "Error": "Viga", "Warning": "Hoiatus", "Notice": "Teade", "Info": "Info", "Debug": "Silumine" } log-viewer/translations/id.json 0000644 00000000463 15002151620 0012627 0 ustar 00 { "Date": "Tanggal", "The list of logs is empty!": "Daftar Log Kosong", "All": "Semua", "Emergency": "Darurat", "Alert": "Waspada", "Critical": "Kritis", "Error": "Kesalahan", "Warning": "Peringatan", "Notice": "Pemberitahuan", "Info": "Info", "Debug": "Debug" } log-viewer/translations/pl.json 0000644 00000000502 15002151620 0012640 0 ustar 00 { "Date": "Data", "The list of logs is empty!": "Lista logów jest pusta!", "All": "Wszystkie", "Emergency": "Awaryjne", "Alert": "Alerty", "Critical": "Krytyczne", "Error": "Błędy", "Warning": "Ostrzeżenia", "Notice": "Warte uwagi", "Info": "Informacje", "Debug": "Debug" } log-viewer/translations/ja.json 0000644 00000000500 15002151620 0012615 0 ustar 00 { "Date": "日付", "The list of logs is empty!": "ログリストが空です!", "All": "すべて", "Emergency": "緊急", "Alert": "警戒", "Critical": "致命的", "Error": "エラー", "Warning": "警告", "Notice": "通知", "Info": "情報", "Debug": "デバッグ" } log-viewer/helpers.php 0000644 00000002044 15002151620 0010767 0 ustar 00 <?php use Arcanedev\LogViewer\Contracts; if ( ! function_exists('log_viewer')) { /** * Get the LogViewer instance. * * @return Arcanedev\LogViewer\Contracts\LogViewer */ function log_viewer() { return app(Contracts\LogViewer::class); } } if ( ! function_exists('log_levels')) { /** * Get the LogLevels instance. * * @return Arcanedev\LogViewer\Contracts\Utilities\LogLevels */ function log_levels() { return app(Contracts\Utilities\LogLevels::class); } } if ( ! function_exists('log_menu')) { /** * Get the LogMenu instance. * * @return Arcanedev\LogViewer\Contracts\Utilities\LogMenu */ function log_menu() { return app(Contracts\Utilities\LogMenu::class); } } if ( ! function_exists('log_styler')) { /** * Get the LogStyler instance. * * @return Arcanedev\LogViewer\Contracts\Utilities\LogStyler */ function log_styler() { return app(Contracts\Utilities\LogStyler::class); } } log-viewer/README.md 0000644 00000012307 15002151620 0010076 0 ustar 00 # LogViewer [![Packagist License][badge_license]](LICENSE.md) [![For Laravel][badge_laravel]][link-github-repo] [![Github Workflow Status][badge_build]][link-github-status] [![Coverage Status][badge_coverage]][link-scrutinizer] [![Scrutinizer Code Quality][badge_quality]][link-scrutinizer] [![SensioLabs Insight][badge_insight]][link-insight] [![Github Issues][badge_issues]][link-github-issues] [![Packagist][badge_package]][link-packagist] [![Packagist Release][badge_release]][link-packagist] [![Packagist Downloads][badge_downloads]][link-packagist] *By [ARCANEDEV©](http://www.arcanedev.net/)* This package allows you to manage and keep track of each one of your log files. > **NOTE: You can also use LogViewer as an API.** Official documentation for LogViewer can be found at the [_docs folder](_docs/1.Installation-and-Setup.md). Feel free to check out the [releases](https://github.com/ARCANEDEV/LogViewer/releases), [license](LICENSE.md), and [contribution guidelines](CONTRIBUTING.md). ## Features - A great Log viewer API. - Laravel `5.x` to `9.x` are supported. - Ready to use (Views, Routes, controllers … Out of the box) [Note: No need to publish assets] - View, paginate, filter, download and delete logs. - Load a custom logs storage path. - Localized log levels. - Logs menu/tree generator. - Grouped logs by dates and levels. - Customized log levels icons (font awesome by default). - Works great with big logs !! - Well documented package (IDE Friendly). - Well tested (100% code coverage with maximum code quality). ## Table of contents 1. [Installation and Setup](_docs/1.Installation-and-Setup.md) 2. [Configuration](_docs/2.Configuration.md) 3. [Usage](_docs/3.Usage.md) 4. [FAQ](_docs/4.FAQ.md) ### Supported localizations > Dear artisans, i'm counting on you to help me out to add more translations ( ^_^)b | Local | Language | |---------|-----------------------| | `ar` | Arabic | | `bg` | Bulgarian | | `de` | German | | `en` | English | | `es` | Spanish | | `et` | Estonian | | `fa` | Farsi | | `fr` | French | | `he` | Hebrew | | `hu` | Hungarian | | `hy` | Armenian | | `id` | Indonesian | | `it` | Italian | | `ja` | Japanese | | `ko` | Korean | | `ms` | Malay | | `nl` | Dutch | | `pl` | Polish | | `pt-BR` | Brazilian Portuguese | | `ro` | Romanian | | `ru` | Russian | | `si` | Sinhalese | | `sv` | Swedish | | `th` | Thai | | `tr` | Turkish | | `uk` | Ukrainian | | `zh` | Chinese (Simplified) | | `zh-TW` | Chinese (Traditional) | ## Contribution Any ideas are welcome. Feel free to submit any issues or pull requests, please check the [contribution guidelines](CONTRIBUTING.md). ## Security If you discover any security related issues, please email arcanedev.maroc@gmail.com instead of using the issue tracker. ## Credits - [ARCANEDEV][link-author] - [All Contributors][link-contributors] ## PREVIEW    [badge_laravel]: https://img.shields.io/badge/Laravel-5.x%20to%209.x-orange.svg?style=flat-square [badge_license]: https://img.shields.io/packagist/l/arcanedev/log-viewer.svg?style=flat-square [badge_build]: https://img.shields.io/github/workflow/status/ARCANEDEV/LogViewer/run-tests?style=flat-square [badge_coverage]: https://img.shields.io/scrutinizer/coverage/g/ARCANEDEV/LogViewer.svg?style=flat-square [badge_quality]: https://img.shields.io/scrutinizer/g/ARCANEDEV/LogViewer.svg?style=flat-square [badge_insight]: https://img.shields.io/sensiolabs/i/d6b4587a-e00d-4dac-98db-f979731fdc4d.svg?style=flat-square [badge_issues]: https://img.shields.io/github/issues/ARCANEDEV/LogViewer.svg?style=flat-square [badge_package]: https://img.shields.io/badge/package-arcanedev/log--viewer-blue.svg?style=flat-square [badge_release]: https://img.shields.io/packagist/v/arcanedev/log-viewer.svg?style=flat-square [badge_downloads]: https://img.shields.io/packagist/dt/arcanedev/log-viewer.svg?style=flat-square [link-author]: https://github.com/arcanedev-maroc [link-github-status]: https://github.com/ARCANEDEV/LogViewer/actions [link-github-repo]: https://github.com/ARCANEDEV/LogViewer [link-github-issues]: https://github.com/ARCANEDEV/LogViewer/issues [link-contributors]: https://github.com/ARCANEDEV/LogViewer/graphs/contributors [link-packagist]: https://packagist.org/packages/arcanedev/log-viewer [link-scrutinizer]: https://scrutinizer-ci.com/g/ARCANEDEV/LogViewer/?branch=master [link-insight]: https://insight.sensiolabs.com/projects/d6b4587a-e00d-4dac-98db-f979731fdc4d log-viewer/views/bootstrap-3/_master.blade.php 0000644 00000025346 15002151620 0015351 0 ustar 00 <!DOCTYPE html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>LogViewer - Created by ARCANEDEV</title> <meta name="description" content="LogViewer"> <meta name="author" content="ARCANEDEV"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> <link href='https://fonts.googleapis.com/css?family=Montserrat:400,700|Source+Sans+Pro:400,600' rel='stylesheet' type='text/css'> <style> html { position: relative; min-height: 100%; } body { padding-top: 50px; /* Margin bottom by footer height */ margin-bottom: 50px; font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, sans-serif; font-weight: 600; } h1, h2, h3 { font-family: 'Montserrat', 'Helvetica Neue', Helvetica, sans-serif; } .sub-header { padding-bottom: 10px; border-bottom: 1px solid #EEE; } .navbar-inverse { background-color: #1a237e; border-color: #1a237e; } .navbar-inverse .navbar-nav>.active>a, .navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover { background-color: #3949ab; } .navbar-inverse .navbar-brand { color: #c5cae9; } .navbar-inverse .navbar-nav>li>a { color: #c5cae9; } .navbar-fixed-top { border: 0; } .main { padding: 20px; } .main .page-header { margin-top: 0; } footer.main-footer { position: absolute; padding: 10px 0; bottom: 0; width: 100%; background-color: #e8eaf6; font-weight: 600; } footer.main-footer p { margin: 0; } footer.main-footer i.fa.fa-heart { color: #C62828; } .pagination { margin: 0; } .pagination > li > a, .pagination > li > span { padding: 4px 10px; } .table-condensed > tbody > tr > td.stack, .table-condensed > tfoot > tr > td.stack, .table-condensed > thead > tr > td.stack { padding: 0; border-top: none; background-color: #F6F6F6; border-top: 1px solid #D1D1D1; max-width: 0; overflow-x: auto; } .table-condensed > tbody > tr > td > p { margin: 0; } .stack-content { padding: 8px; color: #AE0E0E; font-family: consolas, Menlo, Courier, monospace; font-size: 12px; font-weight: 400; white-space: pre-line; } .info-box.level { display: block; padding: 0; margin-bottom: 15px; min-height: 70px; background: #fff; width: 100%; box-shadow: 0 1px 1px rgba(0,0,0,0.1); border-radius: 2px; } .info-box.level .info-box-text, .info-box.level .info-box-number, .info-box.level .info-box-icon > i { text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); } .info-box.level .info-box-text { display: block; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .info-box.level .info-box-content { padding: 5px 10px; margin-left: 70px; } .info-box.level .info-box-number { display: block; font-weight: bold; font-size: 18px; } .info-box.level .info-box-icon { border-radius: 2px 0 0 2px; display: block; float: left; height: 70px; width: 70px; text-align: center; font-size: 40px; line-height: 70px; background: rgba(0,0,0,0.2); } .info-box.level .progress { background: rgba(0,0,0,0.2); margin: 5px -10px 5px -10px; height: 2px; } .info-box.level .progress .progress-bar { background: #fff; } .info-box.level-empty { opacity: .6; -webkit-filter: grayscale(1); -moz-filter: grayscale(1); -ms-filter: grayscale(1); filter: grayscale(1); -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; -o-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; -webkit-transition-property: -webkit-filter, opacity; -moz-transition-property: -moz-filter, opacity; -o-transition-property: filter, opacity; transition-property: -webkit-filter, -moz-filter, -o-filter, filter, opacity; } .info-box.level-empty:hover { opacity: 1; -webkit-filter: grayscale(0); -moz-filter: grayscale(0); -ms-filter: grayscale(0); filter: grayscale(0); } .level { padding: 2px 6px; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); border-radius: 2px; font-size: .9em; font-weight: 600; } .badge.level-all, .badge.level-emergency, .badge.level-alert, .badge.level-critical, .badge.level-error, .badge.level-warning, .badge.level-notice, .badge.level-info, .badge.level-debug, .level, .level i, .info-box.level-all, .info-box.level-emergency, .info-box.level-alert, .info-box.level-critical, .info-box.level-error, .info-box.level-warning, .info-box.level-notice, .info-box.level-info, .info-box.level-debug { color: #FFF; } .label-env { font-size: .85em; } .badge.level-all, .level.level-all, .info-box.level-all { background-color: {{ log_styler()->color('all') }}; } .badge.level-emergency, .level.level-emergency, .info-box.level-emergency { background-color: {{ log_styler()->color('emergency') }}; } .badge.level-alert, .level.level-alert, .info-box.level-alert { background-color: {{ log_styler()->color('alert') }}; } .badge.level-critical, .level.level-critical, .info-box.level-critical { background-color: {{ log_styler()->color('critical') }}; } .badge.level-error, .level.level-error, .info-box.level-error { background-color: {{ log_styler()->color('error') }}; } .badge.level-warning, .level.level-warning, .info-box.level-warning { background-color: {{ log_styler()->color('warning') }}; } .badge.level-notice, .level.level-notice, .info-box.level-notice { background-color: {{ log_styler()->color('notice') }}; } .badge.level-info, .level.level-info, .info-box.level-info { background-color: {{ log_styler()->color('info') }}; } .badge.level-debug, .level.level-debug, .info-box.level-debug { background-color: {{ log_styler()->color('debug') }}; } .badge.level-empty, .level.level-empty { background-color: {{ log_styler()->color('empty') }}; } .badge.label-env, .label.label-env { background-color: #6A1B9A; } </style> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> {{-- Navbar --}} <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">@lang('Toggle navigation')</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="{{ route('log-viewer::dashboard') }}" class="navbar-brand"> <i class="fa fa-fw fa-book"></i> LogViewer </a> </div> <div class="collapse navbar-collapse" id="navbar"> <ul class="nav navbar-nav"> <li class="{{ Route::is('log-viewer::dashboard') ? 'active' : '' }}"> <a href="{{ route('log-viewer::dashboard') }}"> <i class="fa fa-dashboard"></i> @lang('Dashboard') </a> </li> <li class="{{ Route::is('log-viewer::logs.list') ? 'active' : '' }}"> <a href="{{ route('log-viewer::logs.list') }}"> <i class="fa fa-archive"></i> @lang('Logs') </a> </li> </ul> </div> </div> </nav> {{-- Main container --}} <main class="container-fluid"> @yield('content') </main> {{-- Footer --}} <footer class="main-footer"> <div class="container"> <p class="text-muted pull-left"> LogViewer - <span class="label label-info">version {{ log_viewer()->version() }}</span> </p> <p class="text-muted pull-right"> Created with <i class="fa fa-heart"></i> by ARCANEDEV <sup>©</sup> </p> </div> </footer> {{-- Scripts --}} <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.min.js"></script> <script> Chart.defaults.global.responsive = true; Chart.defaults.global.scaleFontFamily = "'Source Sans Pro'"; Chart.defaults.global.animationEasing = "easeOutQuart"; </script> @yield('modals') @yield('scripts') </body> </html> log-viewer/views/bootstrap-3/dashboard.blade.php 0000644 00000003640 15002151620 0015637 0 ustar 00 @extends('log-viewer::bootstrap-3._master') @section('content') <h1 class="page-header">@lang('Dashboard')</h1> <div class="row"> <div class="col-md-3"> <canvas id="stats-doughnut-chart" height="300"></canvas> </div> <div class="col-md-9"> <section class="box-body"> <div class="row"> @foreach($percents as $level => $item) <div class="col-md-4"> <div class="info-box level level-{{ $level }} {{ $item['count'] === 0 ? 'level-empty' : '' }}"> <span class="info-box-icon"> {{ log_styler()->icon($level) }} </span> <div class="info-box-content"> <span class="info-box-text">{{ $item['name'] }}</span> <span class="info-box-number"> {{ $item['count'] }} @lang('entries') - {!! $item['percent'] !!} % </span> <div class="progress"> <div class="progress-bar" style="width: {{ $item['percent'] }}%"></div> </div> </div> </div> </div> @endforeach </div> </section> </div> </div> @endsection @section('scripts') <script> $(function() { new Chart($('canvas#stats-doughnut-chart'), { type: 'doughnut', data: {!! $chartData !!}, options: { legend: { position: 'bottom' } } }); }); </script> @endsection log-viewer/views/bootstrap-3/logs.blade.php 0000644 00000014736 15002151620 0014664 0 ustar 00 @extends('log-viewer::bootstrap-3._master') <?php /** @var Illuminate\Pagination\LengthAwarePaginator $rows */ ?> @section('content') <h1 class="page-header">@lang('Logs')</h1> {{ $rows->render() }} <div class="table-responsive"> <table class="table table-condensed table-hover table-stats"> <thead> <tr> @foreach($headers as $key => $header) <th class="{{ $key == 'date' ? 'text-left' : 'text-center' }}"> @if ($key == 'date') <span class="label label-info">{{ $header }}</span> @else <span class="level level-{{ $key }}"> {{ log_styler()->icon($key) }} {{ $header }} </span> @endif </th> @endforeach <th class="text-right">@lang('Actions')</th> </tr> </thead> <tbody> @forelse($rows as $date => $row) <tr> @foreach($row as $key => $value) <td class="{{ $key == 'date' ? 'text-left' : 'text-center' }}"> @if ($key == 'date') <span class="label label-primary">{{ $value }}</span> @elseif ($value == 0) <span class="level level-empty">{{ $value }}</span> @else <a href="{{ route('log-viewer::logs.filter', [$date, $key]) }}"> <span class="level level-{{ $key }}">{{ $value }}</span> </a> @endif </td> @endforeach <td class="text-right"> <a href="{{ route('log-viewer::logs.show', [$date]) }}" class="btn btn-xs btn-info"> <i class="fa fa-search"></i> </a> <a href="{{ route('log-viewer::logs.download', [$date]) }}" class="btn btn-xs btn-success"> <i class="fa fa-download"></i> </a> <a href="#delete-log-modal" class="btn btn-xs btn-danger" data-log-date="{{ $date }}"> <i class="fa fa-trash-o"></i> </a> </td> </tr> @empty <tr> <td colspan="11" class="text-center"> <span class="label label-default">{{ trans('log-viewer::general.empty-logs') }}</span> </td> </tr> @endforelse </tbody> </table> </div> {{ $rows->render() }} @endsection @section('modals') {{-- DELETE MODAL --}} <div id="delete-log-modal" class="modal fade"> <div class="modal-dialog"> <form id="delete-log-form" action="{{ route('log-viewer::logs.delete') }}" method="POST"> <input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <input type="hidden" name="date" value=""> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> <h4 class="modal-title">@lang('Delete log file')</h4> </div> <div class="modal-body"> <p></p> </div> <div class="modal-footer"> <button type="button" class="btn btn-sm btn-default pull-left" data-dismiss="modal">@lang('Cancel')</button> <button type="submit" class="btn btn-sm btn-danger" data-loading-text="@lang('Loading')…">@lang('Delete')</button> </div> </div> </form> </div> </div> @endsection @section('scripts') <script> $(function () { var deleteLogModal = $('div#delete-log-modal'), deleteLogForm = $('form#delete-log-form'), submitBtn = deleteLogForm.find('button[type=submit]'); $("a[href=#delete-log-modal]").on('click', function(event) { event.preventDefault(); var date = $(this).data('log-date'), message = "@lang('Are you sure you want to DELETE this log file: :date ?')"; deleteLogForm.find('input[name=date]').val(date); deleteLogModal.find('.modal-body p').html(message.replace(':date', date)); deleteLogModal.modal('show'); }); deleteLogForm.on('submit', function(event) { event.preventDefault(); submitBtn.button('loading'); $.ajax({ url: $(this).attr('action'), type: $(this).attr('method'), dataType: 'json', data: $(this).serialize(), success: function(data) { submitBtn.button('reset'); if (data.result === 'success') { deleteLogModal.modal('hide'); location.reload(); } else { alert('AJAX ERROR ! Check the console !'); console.error(data); } }, error: function(xhr, textStatus, errorThrown) { alert('AJAX ERROR ! Check the console !'); console.error(errorThrown); submitBtn.button('reset'); } }); return false; }); deleteLogModal.on('hidden.bs.modal', function() { deleteLogForm.find('input[name=date]').val(''); deleteLogModal.find('.modal-body p').html(''); }); }); </script> @endsection log-viewer/views/bootstrap-3/show.blade.php 0000644 00000033571 15002151620 0014676 0 ustar 00 <?php /** * @var Arcanedev\LogViewer\Entities\Log $log * @var Illuminate\Pagination\LengthAwarePaginator|array<string|int, Arcanedev\LogViewer\Entities\LogEntry> $entries * @var string|null $query */ ?> @extends('log-viewer::bootstrap-3._master') @section('content') <h1 class="page-header">@lang('Log') [{{ $log->date }}]</h1> <div class="row"> <div class="col-md-2"> <div class="panel panel-default"> <div class="panel-heading"><i class="fa fa-fw fa-flag"></i> @lang('Levels')</div> <ul class="list-group"> @foreach($log->menu() as $levelKey => $item) @if ($item['count'] === 0) <a href="#" class="list-group-item disabled"> <span class="badge"> {{ $item['count'] }} </span> {!! $item['icon'] !!} {{ $item['name'] }} </a> @else <a href="{{ $item['url'] }}" class="list-group-item {{ $levelKey }}"> <span class="badge level-{{ $levelKey }}"> {{ $item['count'] }} </span> <span class="level level-{{ $levelKey }}"> {!! $item['icon'] !!} {{ $item['name'] }} </span> </a> @endif @endforeach </ul> </div> </div> <div class="col-md-10"> {{-- Log Details --}} <div class="panel panel-default"> <div class="panel-heading"> @lang('Log info') : <div class="group-btns pull-right"> <a href="{{ route('log-viewer::logs.download', [$log->date]) }}" class="btn btn-xs btn-success"> <i class="fa fa-download"></i> @lang('Download') </a> <a href="#delete-log-modal" class="btn btn-xs btn-danger" data-toggle="modal"> <i class="fa fa-trash-o"></i> @lang('Delete') </a> </div> </div> <div class="table-responsive"> <table class="table table-condensed"> <thead> <tr> <td>@lang('File path') :</td> <td colspan="5">{{ $log->getPath() }}</td> </tr> </thead> <tbody> <tr> <td>@lang('Log entries') :</td> <td> <span class="label label-primary">{{ $entries->total() }}</span> </td> <td>@lang('Size') :</td> <td> <span class="label label-primary">{{ $log->size() }}</span> </td> <td>@lang('Created at') :</td> <td> <span class="label label-primary">{{ $log->createdAt() }}</span> </td> <td>@lang('Updated at') :</td> <td> <span class="label label-primary">{{ $log->updatedAt() }}</span> </td> </tr> </tbody> </table> </div> <div class="panel-footer"> {{-- Search --}} <form action="{{ route('log-viewer::logs.search', [$log->date, $level]) }}" method="GET"> <div class=form-group"> <div class="input-group"> <input id="query" name="query" class="form-control" value="{{ $query }}" placeholder="@lang('Type here to search')"> <span class="input-group-btn"> @unless (is_null($query)) <a href="{{ route('log-viewer::logs.show', [$log->date]) }}" class="btn btn-default"> (@lang(':count results', ['count' => $entries->count()])) <span class="glyphicon glyphicon-remove"></span> </a> @endunless <button id="search-btn" class="btn btn-primary"> <span class="glyphicon glyphicon-search"></span> </button> </span> </div> </div> </form> </div> </div> {{-- Log Entries --}} <div class="panel panel-default"> @if ($entries->hasPages()) <div class="panel-heading"> {{ $entries->appends(compact('query'))->render() }} <span class="label label-info pull-right"> {{ __('Page :current of :last', ['current' => $entries->currentPage(), 'last' => $entries->lastPage()]) }} </span> </div> @endif <div class="table-responsive"> <table id="entries" class="table table-condensed"> <thead> <tr> <th>@lang('ENV')</th> <th style="width: 120px;">@lang('Level')</th> <th style="width: 65px;">@lang('Time')</th> <th>@lang('Header')</th> <th class="text-right">@lang('Actions')</th> </tr> </thead> <tbody> @forelse($entries as $key => $entry) <tr> <td> <span class="label label-env">{{ $entry->env }}</span> </td> <td> <span class="level level-{{ $entry->level }}">{!! $entry->level() !!}</span> </td> <td> <span class="label label-default"> {{ $entry->datetime->format('H:i:s') }} </span> </td> <td> <p>{{ $entry->header }}</p> </td> <td class="text-right"> @if ($entry->hasStack()) <a class="btn btn-xs btn-default" role="button" data-toggle="collapse" href="#log-stack-{{ $key }}" aria-expanded="false" aria-controls="log-stack-{{ $key }}"> <i class="fa fa-toggle-on"></i> @lang('Stack') </a> @endif @if ($entry->hasContext()) <a class="btn btn-xs btn-default" role="button" data-toggle="collapse" href="#log-context-{{ $key }}" aria-expanded="false" aria-controls="log-context-{{ $key }}"> <i class="fa fa-toggle-on"></i> @lang('Context') </a> @endif </td> </tr> @if ($entry->hasStack() || $entry->hasContext()) <tr> <td colspan="5" class="stack"> @if ($entry->hasStack()) <div class="stack-content collapse" id="log-stack-{{ $key }}"> {!! $entry->stack() !!} </div> @endif @if ($entry->hasContext()) <div class="stack-content collapse" id="log-context-{{ $key }}"> <pre>{{ $entry->context() }}</pre> </div> @endif </td> </tr> @endif @empty <tr> <td colspan="5" class="text-center"> <span class="label label-default">@lang('The list of logs is empty!')</span> </td> </tr> @endforelse </tbody> </table> </div> @if ($entries->hasPages()) <div class="panel-footer"> {!! $entries->appends(compact('query'))->render() !!} <span class="label label-info pull-right"> @lang('Page :current of :last', ['current' => $entries->currentPage(), 'last' => $entries->lastPage()]) </span> </div> @endif </div> </div> </div> @endsection @section('modals') {{-- DELETE MODAL --}} <div id="delete-log-modal" class="modal fade"> <div class="modal-dialog"> <form id="delete-log-form" action="{{ route('log-viewer::logs.delete') }}" method="POST"> <input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <input type="hidden" name="date" value="{{ $log->date }}"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> <h4 class="modal-title">@lang('Delete log file')</h4> </div> <div class="modal-body"> <p>@lang('Are you sure you want to delete this log file: :date ?', ['date' => $log->date])</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-sm btn-default pull-left" data-dismiss="modal">@lang('Cancel')</button> <button type="submit" class="btn btn-sm btn-danger" data-loading-text="@lang('Loading')…">@lang('Delete')</button> </div> </div> </form> </div> </div> @endsection @section('scripts') <script> $(function () { var deleteLogModal = $('div#delete-log-modal'), deleteLogForm = $('form#delete-log-form'), submitBtn = deleteLogForm.find('button[type=submit]'); deleteLogForm.on('submit', function(event) { event.preventDefault(); submitBtn.button('loading'); $.ajax({ url: $(this).attr('action'), type: $(this).attr('method'), dataType: 'json', data: $(this).serialize(), success: function(data) { submitBtn.button('reset'); if (data.result === 'success') { deleteLogModal.modal('hide'); location.replace("{{ route('log-viewer::logs.list') }}"); } else { alert('OOPS ! This is a lack of coffee exception !') } }, error: function(xhr, textStatus, errorThrown) { alert('AJAX ERROR ! Check the console !'); console.error(errorThrown); submitBtn.button('reset'); } }); return false; }); @unless (empty(log_styler()->toHighlight())) @php $htmlHighlight = version_compare(PHP_VERSION, '7.4.0') >= 0 ? join('|', log_styler()->toHighlight()) : join(log_styler()->toHighlight(), '|'); @endphp $('.stack-content').each(function() { var $this = $(this); var html = $this.html().trim() .replace(/({!! $htmlHighlight !!})/gm, '<strong>$1</strong>'); $this.html(html); }); @endunless }); </script> @endsection log-viewer/views/bootstrap-4/_master.blade.php 0000644 00000017463 15002151620 0015353 0 ustar 00 <!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content="LogViewer"> <meta name="author" content="ARCANEDEV"> <title>LogViewer - Created by ARCANEDEV</title> {{-- Styles --}} <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> <link href='https://fonts.googleapis.com/css?family=Montserrat:400,700|Source+Sans+Pro:400,600' rel='stylesheet' type='text/css'> <style> html { position: relative; min-height: 100%; } body { font-size: .875rem; margin-bottom: 60px; } .main-footer { position: absolute; bottom: 0; width: 100%; height: 60px; line-height: 60px; background-color: #E8EAF6; } .main-footer p { margin-bottom: 0; } .main-footer .fa.fa-heart { color: #C62828; } .page-header { border-bottom: 1px solid #8a8a8a; } /* * Navbar */ .navbar-brand { padding: .75rem 1rem; font-size: 1rem; } .navbar-nav .nav-link { padding-right: .5rem; padding-left: .5rem; } /* * Boxes */ .box { display: block; padding: 0; min-height: 70px; background: #fff; width: 100%; box-shadow: 0 1px 1px rgba(0,0,0,0.1); border-radius: .25rem; } .box > .box-icon > i, .box .box-content .box-text, .box .box-content .box-number { color: #FFF; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); } .box > .box-icon { border-radius: 2px 0 0 2px; display: block; float: left; height: 70px; width: 70px; text-align: center; font-size: 40px; line-height: 70px; background: rgba(0,0,0,0.2); } .box .box-content { padding: 5px 10px; margin-left: 70px; } .box .box-content .box-text { display: block; font-size: 1rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; } .box .box-content .box-number { display: block; } .box .box-content .progress { background: rgba(0,0,0,0.2); margin: 5px -10px 5px -10px; } .box .box-content .progress .progress-bar { background-color: #FFF; } /* * Log Menu */ .log-menu .list-group-item.disabled { cursor: not-allowed; } .log-menu .list-group-item.disabled .level-name { color: #D1D1D1; } /* * Log Entry */ .stack-content { color: #AE0E0E; font-family: consolas, Menlo, Courier, monospace; white-space: pre-line; font-size: .8rem; } /* * Colors: Badge & Infobox */ .badge.badge-env, .badge.badge-level-all, .badge.badge-level-emergency, .badge.badge-level-alert, .badge.badge-level-critical, .badge.badge-level-error, .badge.badge-level-warning, .badge.badge-level-notice, .badge.badge-level-info, .badge.badge-level-debug, .badge.empty { color: #FFF; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); } .badge.badge-level-all, .box.level-all { background-color: {{ log_styler()->color('all') }}; } .badge.badge-level-emergency, .box.level-emergency { background-color: {{ log_styler()->color('emergency') }}; } .badge.badge-level-alert, .box.level-alert { background-color: {{ log_styler()->color('alert') }}; } .badge.badge-level-critical, .box.level-critical { background-color: {{ log_styler()->color('critical') }}; } .badge.badge-level-error, .box.level-error { background-color: {{ log_styler()->color('error') }}; } .badge.badge-level-warning, .box.level-warning { background-color: {{ log_styler()->color('warning') }}; } .badge.badge-level-notice, .box.level-notice { background-color: {{ log_styler()->color('notice') }}; } .badge.badge-level-info, .box.level-info { background-color: {{ log_styler()->color('info') }}; } .badge.badge-level-debug, .box.level-debug { background-color: {{ log_styler()->color('debug') }}; } .badge.empty, .box.empty { background-color: {{ log_styler()->color('empty') }}; } .badge.badge-env { background-color: #6A1B9A; } #entries { overflow-wrap: anywhere; } </style> </head> <body> <nav class="navbar navbar-expand-md navbar-dark sticky-top bg-dark p-0"> <a href="{{ route('log-viewer::dashboard') }}" class="navbar-brand mr-0"> <i class="fa fa-fw fa-book"></i> LogViewer </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav mr-auto"> <li class="nav-item {{ Route::is('log-viewer::dashboard') ? 'active' : '' }}"> <a href="{{ route('log-viewer::dashboard') }}" class="nav-link"> <i class="fa fa-dashboard"></i> @lang('Dashboard') </a> </li> <li class="nav-item {{ Route::is('log-viewer::logs.list') ? 'active' : '' }}"> <a href="{{ route('log-viewer::logs.list') }}" class="nav-link"> <i class="fa fa-archive"></i> @lang('Logs') </a> </li> </ul> </div> </nav> <div class="container-fluid"> <main role="main" class="pt-3"> @yield('content') </main> </div> {{-- Footer --}} <footer class="main-footer"> <div class="container-fluid"> <p class="text-muted pull-left"> LogViewer - <span class="badge badge-info">version {{ log_viewer()->version() }}</span> </p> <p class="text-muted pull-right"> Created with <i class="fa fa-heart"></i> by ARCANEDEV <sup>©</sup> </p> </div> </footer> {{-- Scripts --}} <script src="https://code.jquery.com/jquery-3.2.1.min.js" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script> @yield('modals') @yield('scripts') </body> </html> log-viewer/views/bootstrap-4/dashboard.blade.php 0000644 00000003547 15002151620 0015646 0 ustar 00 @extends('log-viewer::bootstrap-4._master') @section('content') <div class="page-header mb-4"> <h1>@lang('Dashboard')</h1> </div> <div class="row"> <div class="col-md-6 col-lg-3"> <canvas id="stats-doughnut-chart" height="300" class="mb-3"></canvas> </div> <div class="col-md-6 col-lg-9"> <div class="row"> @foreach($percents as $level => $item) <div class="col-sm-6 col-md-12 col-lg-4 mb-3"> <div class="box level-{{ $level }} {{ $item['count'] === 0 ? 'empty' : '' }}"> <div class="box-icon"> {!! log_styler()->icon($level) !!} </div> <div class="box-content"> <span class="box-text">{{ $item['name'] }}</span> <span class="box-number"> {{ $item['count'] }} @lang('entries') - {!! $item['percent'] !!} % </span> <div class="progress" style="height: 3px;"> <div class="progress-bar" style="width: {{ $item['percent'] }}%"></div> </div> </div> </div> </div> @endforeach </div> </div> </div> @endsection @section('scripts') <script> $(function() { new Chart(document.getElementById("stats-doughnut-chart"), { type: 'doughnut', data: {!! $chartData !!}, options: { legend: { position: 'bottom' } } }); }); </script> @endsection log-viewer/views/bootstrap-4/logs.blade.php 0000644 00000015025 15002151620 0014655 0 ustar 00 @extends('log-viewer::bootstrap-4._master') <?php /** @var Illuminate\Pagination\LengthAwarePaginator $rows */ ?> @section('content') <div class="page-header mb-4"> <h1>@lang('Logs')</h1> </div> <div class="table-responsive"> <table class="table table-sm table-hover"> <thead> <tr> @foreach($headers as $key => $header) <th scope="col" class="{{ $key == 'date' ? 'text-left' : 'text-center' }}"> @if ($key == 'date') <span class="badge badge-info">{{ $header }}</span> @else <span class="badge badge-level-{{ $key }}"> {{ log_styler()->icon($key) }} {{ $header }} </span> @endif </th> @endforeach <th scope="col" class="text-right">@lang('Actions')</th> </tr> </thead> <tbody> @forelse($rows as $date => $row) <tr> @foreach($row as $key => $value) <td class="{{ $key == 'date' ? 'text-left' : 'text-center' }}"> @if ($key == 'date') <span class="badge badge-primary">{{ $value }}</span> @elseif ($value == 0) <span class="badge empty">{{ $value }}</span> @else <a href="{{ route('log-viewer::logs.filter', [$date, $key]) }}"> <span class="badge badge-level-{{ $key }}">{{ $value }}</span> </a> @endif </td> @endforeach <td class="text-right"> <a href="{{ route('log-viewer::logs.show', [$date]) }}" class="btn btn-sm btn-info"> <i class="fa fa-search"></i> </a> <a href="{{ route('log-viewer::logs.download', [$date]) }}" class="btn btn-sm btn-success"> <i class="fa fa-download"></i> </a> <a href="#delete-log-modal" class="btn btn-sm btn-danger" data-log-date="{{ $date }}"> <i class="fa fa-trash-o"></i> </a> </td> </tr> @empty <tr> <td colspan="11" class="text-center"> <span class="badge badge-secondary">@lang('The list of logs is empty!')</span> </td> </tr> @endforelse </tbody> </table> </div> {{ $rows->render() }} @endsection @section('modals') {{-- DELETE MODAL --}} <div id="delete-log-modal" class="modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <form id="delete-log-form" action="{{ route('log-viewer::logs.delete') }}" method="POST"> <input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <input type="hidden" name="date" value=""> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">@lang('Delete log file')</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <p></p> </div> <div class="modal-footer"> <button type="button" class="btn btn-sm btn-secondary mr-auto" data-dismiss="modal">@lang('Cancel')</button> <button type="submit" class="btn btn-sm btn-danger" data-loading-text="@lang('Loading')…">@lang('Delete')</button> </div> </div> </form> </div> </div> @endsection @section('scripts') <script> $(function () { var deleteLogModal = $('div#delete-log-modal'), deleteLogForm = $('form#delete-log-form'), submitBtn = deleteLogForm.find('button[type=submit]'); $("a[href='#delete-log-modal']").on('click', function(event) { event.preventDefault(); var date = $(this).data('log-date'), message = "{{ __('Are you sure you want to delete this log file: :date ?') }}"; deleteLogForm.find('input[name=date]').val(date); deleteLogModal.find('.modal-body p').html(message.replace(':date', date)); deleteLogModal.modal('show'); }); deleteLogForm.on('submit', function(event) { event.preventDefault(); submitBtn.button('loading'); $.ajax({ url: $(this).attr('action'), type: $(this).attr('method'), dataType: 'json', data: $(this).serialize(), success: function(data) { submitBtn.button('reset'); if (data.result === 'success') { deleteLogModal.modal('hide'); location.reload(); } else { alert('AJAX ERROR ! Check the console !'); console.error(data); } }, error: function(xhr, textStatus, errorThrown) { alert('AJAX ERROR ! Check the console !'); console.error(errorThrown); submitBtn.button('reset'); } }); return false; }); deleteLogModal.on('hidden.bs.modal', function() { deleteLogForm.find('input[name=date]').val(''); deleteLogModal.find('.modal-body p').html(''); }); }); </script> @endsection log-viewer/views/bootstrap-4/show.blade.php 0000644 00000033017 15002151620 0014672 0 ustar 00 <?php /** * @var Arcanedev\LogViewer\Entities\Log $log * @var Illuminate\Pagination\LengthAwarePaginator|array<string|int, Arcanedev\LogViewer\Entities\LogEntry> $entries * @var string|null $query */ ?> @extends('log-viewer::bootstrap-4._master') @section('content') <div class="page-header mb-4"> <h1>@lang('Log') [{{ $log->date }}]</h1> </div> <div class="row"> <div class="col-lg-2"> {{-- Log Menu --}} <div class="card mb-4"> <div class="card-header"><i class="fa fa-fw fa-flag"></i> @lang('Levels')</div> <div class="list-group list-group-flush log-menu"> @foreach($log->menu() as $levelKey => $item) @if ($item['count'] === 0) <a class="list-group-item list-group-item-action d-flex justify-content-between align-items-center disabled"> <span class="level-name">{!! $item['icon'] !!} {{ $item['name'] }}</span> <span class="badge empty">{{ $item['count'] }}</span> </a> @else <a href="{{ $item['url'] }}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center level-{{ $levelKey }}{{ $level === $levelKey ? ' active' : ''}}"> <span class="level-name">{!! $item['icon'] !!} {{ $item['name'] }}</span> <span class="badge badge-level-{{ $levelKey }}">{{ $item['count'] }}</span> </a> @endif @endforeach </div> </div> </div> <div class="col-lg-10"> {{-- Log Details --}} <div class="card mb-4"> <div class="card-header"> @lang('Log info') : <div class="group-btns pull-right"> <a href="{{ route('log-viewer::logs.download', [$log->date]) }}" class="btn btn-sm btn-success"> <i class="fa fa-download"></i> @lang('Download') </a> <a href="#delete-log-modal" class="btn btn-sm btn-danger" data-toggle="modal"> <i class="fa fa-trash-o"></i> @lang('Delete') </a> </div> </div> <div class="table-responsive"> <table class="table table-condensed mb-0"> <tbody> <tr> <td>@lang('File path') :</td> <td colspan="7">{{ $log->getPath() }}</td> </tr> <tr> <td>@lang('Log entries') :</td> <td> <span class="badge badge-primary">{{ $entries->total() }}</span> </td> <td>@lang('Size') :</td> <td> <span class="badge badge-primary">{{ $log->size() }}</span> </td> <td>@lang('Created at') :</td> <td> <span class="badge badge-primary">{{ $log->createdAt() }}</span> </td> <td>@lang('Updated at') :</td> <td> <span class="badge badge-primary">{{ $log->updatedAt() }}</span> </td> </tr> </tbody> </table> </div> <div class="card-footer"> {{-- Search --}} <form action="{{ route('log-viewer::logs.search', [$log->date, $level]) }}" method="GET"> <div class="form-group"> <div class="input-group"> <input id="query" name="query" class="form-control" value="{{ $query }}" placeholder="@lang('Type here to search')"> <div class="input-group-append"> @unless (is_null($query)) <a href="{{ route('log-viewer::logs.show', [$log->date]) }}" class="btn btn-secondary"> (@lang(':count results', ['count' => $entries->count()])) <i class="fa fa-fw fa-times"></i> </a> @endunless <button id="search-btn" class="btn btn-primary"> <span class="fa fa-fw fa-search"></span> </button> </div> </div> </div> </form> </div> </div> {{-- Log Entries --}} <div class="card mb-4"> @if ($entries->hasPages()) <div class="card-header"> <span class="badge badge-info float-right"> {{ __('Page :current of :last', ['current' => $entries->currentPage(), 'last' => $entries->lastPage()]) }} </span> </div> @endif <div class="table-responsive"> <table id="entries" class="table mb-0"> <thead> <tr> <th>@lang('ENV')</th> <th style="width: 120px;">@lang('Level')</th> <th style="width: 65px;">@lang('Time')</th> <th>@lang('Header')</th> <th class="text-right">@lang('Actions')</th> </tr> </thead> <tbody> @forelse($entries as $key => $entry) <tr> <td> <span class="badge badge-env">{{ $entry->env }}</span> </td> <td> <span class="badge badge-level-{{ $entry->level }}"> {!! $entry->level() !!} </span> </td> <td> <span class="badge badge-secondary"> {{ $entry->datetime->format('H:i:s') }} </span> </td> <td> {{ $entry->header }} </td> <td class="text-right"> @if ($entry->hasStack()) <a class="btn btn-sm btn-light" role="button" data-toggle="collapse" href="#log-stack-{{ $key }}" aria-expanded="false" aria-controls="log-stack-{{ $key }}"> <i class="fa fa-toggle-on"></i> @lang('Stack') </a> @endif @if ($entry->hasContext()) <a class="btn btn-sm btn-light" role="button" data-toggle="collapse" href="#log-context-{{ $key }}" aria-expanded="false" aria-controls="log-context-{{ $key }}"> <i class="fa fa-toggle-on"></i> @lang('Context') </a> @endif </td> </tr> @if ($entry->hasStack() || $entry->hasContext()) <tr> <td colspan="5" class="stack py-0"> @if ($entry->hasStack()) <div class="stack-content collapse" id="log-stack-{{ $key }}"> {!! $entry->stack() !!} </div> @endif @if ($entry->hasContext()) <div class="stack-content collapse" id="log-context-{{ $key }}"> <pre>{{ $entry->context() }}</pre> </div> @endif </td> </tr> @endif @empty <tr> <td colspan="5" class="text-center"> <span class="badge badge-secondary">@lang('The list of logs is empty!')</span> </td> </tr> @endforelse </tbody> </table> </div> </div> {!! $entries->appends(compact('query'))->render() !!} </div> </div> @endsection @section('modals') {{-- DELETE MODAL --}} <div id="delete-log-modal" class="modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <form id="delete-log-form" action="{{ route('log-viewer::logs.delete') }}" method="POST"> <input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <input type="hidden" name="date" value="{{ $log->date }}"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">@lang('Delete log file')</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <p>@lang('Are you sure you want to delete this log file: :date ?', ['date' => $log->date])</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-sm btn-secondary mr-auto" data-dismiss="modal">@lang('Cancel')</button> <button type="submit" class="btn btn-sm btn-danger" data-loading-text="@lang('Loading')…">@lang('Delete')</button> </div> </div> </form> </div> </div> @endsection @section('scripts') <script> $(function () { var deleteLogModal = $('div#delete-log-modal'), deleteLogForm = $('form#delete-log-form'), submitBtn = deleteLogForm.find('button[type=submit]'); deleteLogForm.on('submit', function(event) { event.preventDefault(); submitBtn.button('loading'); $.ajax({ url: $(this).attr('action'), type: $(this).attr('method'), dataType: 'json', data: $(this).serialize(), success: function(data) { submitBtn.button('reset'); if (data.result === 'success') { deleteLogModal.modal('hide'); location.replace("{{ route('log-viewer::logs.list') }}"); } else { alert('OOPS ! This is a lack of coffee exception !') } }, error: function(xhr, textStatus, errorThrown) { alert('AJAX ERROR ! Check the console !'); console.error(errorThrown); submitBtn.button('reset'); } }); return false; }); @unless (empty(log_styler()->toHighlight())) @php $htmlHighlight = version_compare(PHP_VERSION, '7.4.0') >= 0 ? join('|', log_styler()->toHighlight()) : join(log_styler()->toHighlight(), '|'); @endphp $('.stack-content').each(function() { var $this = $(this); var html = $this.html().trim() .replace(/({!! $htmlHighlight !!})/gm, '<strong>$1</strong>'); $this.html(html); }); @endunless }); </script> @endsection log-viewer/src/Utilities/LogChecker.php 0000644 00000016106 15002151620 0014101 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Utilities; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem as FilesystemContract; use Arcanedev\LogViewer\Contracts\Utilities\LogChecker as LogCheckerContract; use Illuminate\Contracts\Config\Repository as ConfigContract; /** * Class LogChecker * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogChecker implements LogCheckerContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The config repository instance. * * @var \Illuminate\Contracts\Config\Repository */ private $config; /** * The filesystem instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\Filesystem */ private $filesystem; /** * Log handler mode. * * @var string */ protected $handler = ''; /** * The check status. * * @var bool */ private $status = true; /** * The check messages. * * @var array */ private $messages; /** * Log files statuses. * * @var array */ private $files = []; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * LogChecker constructor. * * @param \Illuminate\Contracts\Config\Repository $config * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem */ public function __construct(ConfigContract $config, FilesystemContract $filesystem) { $this->setConfig($config); $this->setFilesystem($filesystem); $this->refresh(); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the config instance. * * @param \Illuminate\Contracts\Config\Repository $config * * @return self */ public function setConfig(ConfigContract $config) { $this->config = $config; return $this; } /** * Set the Filesystem instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * * @return self */ public function setFilesystem(FilesystemContract $filesystem) { $this->filesystem = $filesystem; return $this; } /** * Set the log handler mode. * * @param string $handler * * @return self */ protected function setHandler($handler) { $this->handler = strtolower($handler); return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get messages. * * @return array */ public function messages() { $this->refresh(); return $this->messages; } /** * Check if the checker passes. * * @return bool */ public function passes() { $this->refresh(); return $this->status; } /** * Check if the checker fails. * * @return bool */ public function fails() { return ! $this->passes(); } /** * Get the requirements. * * @return array */ public function requirements() { $this->refresh(); return $this->isDaily() ? [ 'status' => 'success', 'header' => 'Application requirements fulfilled.', 'message' => 'Are you ready to rock ?', ] : [ 'status' => 'failed', 'header' => 'Application requirements failed.', 'message' => $this->messages['handler'] ]; } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Is a daily handler mode ? * * @return bool */ protected function isDaily() { return $this->isSameHandler(self::HANDLER_DAILY); } /** * Is the handler is the same as the application log handler. * * @param string $handler * * @return bool */ private function isSameHandler($handler) { return $this->handler === $handler; } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Refresh the checks. * * @return \Arcanedev\LogViewer\Utilities\LogChecker */ private function refresh() { $this->setHandler($this->config->get('logging.default', 'stack')); $this->messages = [ 'handler' => '', 'files' => [], ]; $this->files = []; $this->checkHandler(); $this->checkLogFiles(); return $this; } /** * Check the handler mode. */ private function checkHandler() { if ($this->isDaily()) return; $this->messages['handler'] = 'You should set the log handler to `daily` mode. Please check the LogViewer wiki page (Requirements) for more details.'; } /** * Check all log files. */ private function checkLogFiles() { foreach ($this->filesystem->all() as $path) { $this->checkLogFile($path); } } /** * Check a log file. * * @param string $path */ private function checkLogFile($path) { $status = true; $filename = basename($path); $message = "The log file [$filename] is valid."; $pattern = $this->filesystem->getPattern(); if ($this->isSingleLogFile($filename)) { $this->status = $status = false; $this->messages['files'][$filename] = $message = "You have a single log file in your application, you should split the [$filename] into separate log files."; } elseif ($this->isInvalidLogPattern($filename, $pattern)) { $this->status = $status = false; $this->messages['files'][$filename] = $message = "The log file [$filename] has an invalid date, the format must be like {$pattern}."; } $this->files[$filename] = compact('filename', 'status', 'message', 'path'); } /** * Check if it's not a single log file. * * @param string $file * * @return bool */ private function isSingleLogFile($file) { return $file === 'laravel.log'; } /** * Check the date of the log file. * * @param string $file * @param string $pattern * * @return bool */ private function isInvalidLogPattern($file, $pattern) { return ((bool) preg_match("/{$pattern}/", $file, $matches)) === false; } } log-viewer/src/Utilities/Filesystem.php 0000644 00000016126 15002151620 0014221 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Utilities; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem as FilesystemContract; use Arcanedev\LogViewer\Exceptions\FilesystemException; use Arcanedev\LogViewer\Helpers\LogParser; use Exception; use Illuminate\Filesystem\Filesystem as IlluminateFilesystem; /** * Class Filesystem * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class Filesystem implements FilesystemContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $filesystem; /** * The base storage path. * * @var string */ protected $storagePath; /** * The log files prefix pattern. * * @var string */ protected $prefixPattern; /** * The log files date pattern. * * @var string */ protected $datePattern; /** * The log files extension. * * @var string */ protected $extension; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Filesystem constructor. * * @param \Illuminate\Filesystem\Filesystem $files * @param string $storagePath */ public function __construct(IlluminateFilesystem $files, $storagePath) { $this->filesystem = $files; $this->setPath($storagePath); $this->setPattern(); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the files instance. * * @return \Illuminate\Filesystem\Filesystem */ public function getInstance() { return $this->filesystem; } /** * Set the log storage path. * * @param string $storagePath * * @return $this */ public function setPath($storagePath) { $this->storagePath = $storagePath; return $this; } /** * Get the log pattern. * * @return string */ public function getPattern(): string { return $this->prefixPattern.$this->datePattern.$this->extension; } /** * Set the log pattern. * * @param string $date * @param string $prefix * @param string $extension * * @return $this */ public function setPattern( $prefix = self::PATTERN_PREFIX, $date = self::PATTERN_DATE, $extension = self::PATTERN_EXTENSION ) { $this->setPrefixPattern($prefix); $this->setDatePattern($date); $this->setExtension($extension); return $this; } /** * Set the log date pattern. * * @param string $datePattern * * @return $this */ public function setDatePattern($datePattern) { $this->datePattern = $datePattern; return $this; } /** * Set the log prefix pattern. * * @param string $prefixPattern * * @return $this */ public function setPrefixPattern($prefixPattern) { $this->prefixPattern = $prefixPattern; return $this; } /** * Set the log extension. * * @param string $extension * * @return $this */ public function setExtension($extension) { $this->extension = $extension; return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get all log files. * * @return array */ public function all() { return $this->getFiles('*'.$this->extension); } /** * Get all valid log files. * * @return array */ public function logs() { return $this->getFiles($this->getPattern()); } /** * List the log files (Only dates). * * @param bool $withPaths * * @return array */ public function dates($withPaths = false) { $files = array_reverse($this->logs()); $dates = $this->extractDates($files); if ($withPaths) { $dates = array_combine($dates, $files); // [date => file] } return $dates; } /** * Read the log. * * @param string $date * * @return string * * @throws \Arcanedev\LogViewer\Exceptions\FilesystemException */ public function read($date) { try { $log = $this->filesystem->get( $this->getLogPath($date) ); } catch (Exception $e) { throw new FilesystemException($e->getMessage()); } return $log; } /** * Delete the log. * * @param string $date * * @return bool * * @throws \Arcanedev\LogViewer\Exceptions\FilesystemException */ public function delete(string $date) { $path = $this->getLogPath($date); throw_unless($this->filesystem->delete($path), FilesystemException::cannotDeleteLog()); return true; } /** * Clear the log files. * * @return bool */ public function clear() { return $this->filesystem->delete($this->logs()); } /** * Get the log file path. * * @param string $date * * @return string */ public function path($date) { return $this->getLogPath($date); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get all files. * * @param string $pattern * * @return array */ private function getFiles($pattern) { $files = $this->filesystem->glob( $this->storagePath.DIRECTORY_SEPARATOR.$pattern, defined('GLOB_BRACE') ? GLOB_BRACE : 0 ); return array_filter(array_map('realpath', $files)); } /** * Get the log file path. * * @param string $date * * @return string * * @throws \Arcanedev\LogViewer\Exceptions\FilesystemException */ private function getLogPath(string $date) { $path = $this->storagePath.DIRECTORY_SEPARATOR.$this->prefixPattern.$date.$this->extension; if ( ! $this->filesystem->exists($path)) { throw FilesystemException::invalidPath($path); } return realpath($path); } /** * Extract dates from files. * * @param array $files * * @return array */ private function extractDates(array $files) { return array_map(function ($file) { return LogParser::extractDate(basename($file)); }, $files); } } log-viewer/src/Utilities/LogMenu.php 0000644 00000007346 15002151620 0013447 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Utilities; use Arcanedev\LogViewer\Contracts\Utilities\LogMenu as LogMenuContract; use Arcanedev\LogViewer\Contracts\Utilities\LogStyler as LogStylerContract; use Arcanedev\LogViewer\Entities\Log; use Illuminate\Contracts\Config\Repository as ConfigContract; /** * Class LogMenu * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogMenu implements LogMenuContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The config repository instance. * * @var \Illuminate\Contracts\Config\Repository */ protected $config; /** * The log styler instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\LogStyler */ private $styler; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * LogMenu constructor. * * @param \Illuminate\Contracts\Config\Repository $config * @param \Arcanedev\LogViewer\Contracts\Utilities\LogStyler $styler */ public function __construct(ConfigContract $config, LogStylerContract $styler) { $this->setConfig($config); $this->setLogStyler($styler); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the config instance. * * @param \Illuminate\Contracts\Config\Repository $config * * @return self */ public function setConfig(ConfigContract $config) { $this->config = $config; return $this; } /** * Set the log styler instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\LogStyler $styler * * @return self */ public function setLogStyler(LogStylerContract $styler) { $this->styler = $styler; return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Make log menu. * * @param \Arcanedev\LogViewer\Entities\Log $log * @param bool $trans * * @return array */ public function make(Log $log, $trans = true) { $items = []; $route = $this->config('menu.filter-route'); foreach($log->tree($trans) as $level => $item) { $items[$level] = array_merge($item, [ 'url' => route($route, [$log->date, $level]), 'icon' => $this->isIconsEnabled() ? $this->styler->icon($level)->toHtml() : '', ]); } return $items; } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Check if the icons are enabled. * * @return bool */ private function isIconsEnabled() { return (bool) $this->config('menu.icons-enabled', false); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get config. * * @param string $key * @param mixed $default * * @return mixed */ private function config($key, $default = null) { return $this->config->get("log-viewer.$key", $default); } } log-viewer/src/Utilities/LogStyler.php 0000644 00000004770 15002151620 0014023 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Utilities; use Arcanedev\LogViewer\Contracts\Utilities\LogStyler as LogStylerContract; use Illuminate\Contracts\Config\Repository as ConfigContract; use Illuminate\Support\HtmlString; /** * Class LogStyler * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogStyler implements LogStylerContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The config repository instance. * * @var \Illuminate\Contracts\Config\Repository */ protected $config; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create a new instance. * * @param \Illuminate\Contracts\Config\Repository $config */ public function __construct(ConfigContract $config) { $this->config = $config; } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get config. * * @param string $key * @param mixed $default * * @return mixed */ private function get($key, $default = null) { return $this->config->get("log-viewer.$key", $default); } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Make level icon. * * @param string $level * @param string|null $default * * @return \Illuminate\Support\HtmlString */ public function icon($level, $default = null) { return new HtmlString( '<i class="'.$this->get("icons.$level", $default).'"></i>' ); } /** * Get level color. * * @param string $level * @param string|null $default * * @return string */ public function color($level, $default = null) { return $this->get("colors.levels.$level", $default); } /** * Get strings to highlight. * * @param array $default * * @return array */ public function toHighlight(array $default = []) { return $this->get('highlight', $default); } } log-viewer/src/Utilities/Factory.php 0000644 00000016061 15002151620 0013502 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Utilities; use Arcanedev\LogViewer\Contracts\Utilities\Factory as FactoryContract; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem as FilesystemContract; use Arcanedev\LogViewer\Contracts\Utilities\LogLevels as LogLevelsContract; use Arcanedev\LogViewer\Entities\LogCollection; use Arcanedev\LogViewer\Entities\Log; use Arcanedev\LogViewer\Exceptions\LogNotFoundException; use Arcanedev\LogViewer\Tables\StatsTable; /** * Class Factory * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class Factory implements FactoryContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The filesystem instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\Filesystem */ protected $filesystem; /** * The log levels instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\LogLevels */ private $levels; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create a new instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels */ public function __construct(FilesystemContract $filesystem, LogLevelsContract $levels) { $this->setFilesystem($filesystem); $this->setLevels($levels); } /* ----------------------------------------------------------------- | Getter & Setters | ----------------------------------------------------------------- */ /** * Get the filesystem instance. * * @return \Arcanedev\LogViewer\Contracts\Utilities\Filesystem */ public function getFilesystem() { return $this->filesystem; } /** * Set the filesystem instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * * @return self */ public function setFilesystem(FilesystemContract $filesystem) { $this->filesystem = $filesystem; return $this; } /** * Get the log levels instance. * * @return \Arcanedev\LogViewer\Contracts\Utilities\LogLevels */ public function getLevels() { return $this->levels; } /** * Set the log levels instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels * * @return self */ public function setLevels(LogLevelsContract $levels) { $this->levels = $levels; return $this; } /** * Set the log storage path. * * @param string $storagePath * * @return self */ public function setPath($storagePath) { $this->filesystem->setPath($storagePath); return $this; } /** * Get the log pattern. * * @return string */ public function getPattern() { return $this->filesystem->getPattern(); } /** * Set the log pattern. * * @param string $date * @param string $prefix * @param string $extension * * @return self */ public function setPattern( $prefix = FilesystemContract::PATTERN_PREFIX, $date = FilesystemContract::PATTERN_DATE, $extension = FilesystemContract::PATTERN_EXTENSION ) { $this->filesystem->setPattern($prefix, $date, $extension); return $this; } /** * Get all logs. * * @return \Arcanedev\LogViewer\Entities\LogCollection */ public function logs() { return (new LogCollection)->setFilesystem($this->filesystem); } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get all logs (alias). * * @see logs * * @return \Arcanedev\LogViewer\Entities\LogCollection */ public function all() { return $this->logs(); } /** * Paginate all logs. * * @param int $perPage * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 30) { return $this->logs()->paginate($perPage); } /** * Get a log by date. * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function log($date) { $dates = $this->filesystem->dates(true); if (!isset($dates[$date])) { throw new LogNotFoundException("Log not found in this date [$date]"); } return new Log($date, $dates[$date], $this->filesystem->read($date)); } /** * Get a log by date (alias). * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function get($date) { return $this->log($date); } /** * Get log entries. * * @param string $date * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function entries($date, $level = 'all') { return $this->log($date)->entries($level); } /** * Get logs statistics. * * @return array */ public function stats() { return $this->logs()->stats(); } /** * Get logs statistics table. * * @param string|null $locale * * @return \Arcanedev\LogViewer\Tables\StatsTable */ public function statsTable($locale = null) { return StatsTable::make($this->stats(), $this->levels, $locale); } /** * List the log files (dates). * * @return array */ public function dates() { return $this->filesystem->dates(); } /** * Get logs count. * * @return int */ public function count() { return $this->logs()->count(); } /** * Get total log entries. * * @param string $level * * @return int */ public function total($level = 'all') { return $this->logs()->total($level); } /** * Get tree menu. * * @param bool $trans * * @return array */ public function tree($trans = false) { return $this->logs()->tree($trans); } /** * Get tree menu. * * @param bool $trans * * @return array */ public function menu($trans = true) { return $this->logs()->menu($trans); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Determine if the log folder is empty or not. * * @return bool */ public function isEmpty() { return $this->logs()->isEmpty(); } } log-viewer/src/Utilities/LogLevels.php 0000644 00000010171 15002151620 0013763 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Utilities; use Arcanedev\LogViewer\Contracts\Utilities\LogLevels as LogLevelsContract; use Illuminate\Support\Arr; use Illuminate\Translation\Translator; use Psr\Log\LogLevel; use ReflectionClass; /** * Class LogLevels * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogLevels implements LogLevelsContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The log levels. * * @var array */ protected static $levels = []; /** * The Translator instance. * * @var \Illuminate\Translation\Translator */ private $translator; /** * The selected locale. * * @var string */ private $locale; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * LogLevels constructor. * * @param \Illuminate\Translation\Translator $translator * @param string $locale */ public function __construct(Translator $translator, $locale) { $this->setTranslator($translator); $this->setLocale($locale); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the Translator instance. * * @param \Illuminate\Translation\Translator $translator * * @return $this */ public function setTranslator(Translator $translator) { $this->translator = $translator; return $this; } /** * Get the selected locale. * * @return string */ public function getLocale() { return $this->locale === 'auto' ? $this->translator->getLocale() : $this->locale; } /** * Set the selected locale. * * @param string $locale * * @return $this */ public function setLocale($locale) { $this->locale = is_null($locale) ? 'auto' : $locale; return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get the log levels. * * @param bool $flip * * @return array */ public function lists($flip = false) { return static::all($flip); } /** * Get translated levels. * * @param string|null $locale * * @return array */ public function names($locale = null) { $levels = static::all(true); array_walk($levels, function (&$name, $level) use ($locale) { $name = $this->get($level, $locale); }); return $levels; } /** * Get PSR log levels. * * @param bool $flip * * @return array */ public static function all($flip = false) { if (empty(static::$levels)) { static::$levels = (new ReflectionClass(LogLevel::class))->getConstants(); } return $flip ? array_flip(static::$levels) : static::$levels; } /** * Get the translated level. * * @param string $key * @param string|null $locale * * @return string */ public function get($key, $locale = null) { $translations = [ 'all' => 'All', LogLevel::EMERGENCY => 'Emergency', LogLevel::ALERT => 'Alert', LogLevel::CRITICAL => 'Critical', LogLevel::ERROR => 'Error', LogLevel::WARNING => 'Warning', LogLevel::NOTICE => 'Notice', LogLevel::INFO => 'Info', LogLevel::DEBUG => 'Debug', ]; return $this->translator->get(Arr::get($translations, $key, $key), [], $locale ?: $this->getLocale()); } } log-viewer/src/Exceptions/LogNotFoundException.php 0000644 00000000717 15002151620 0016317 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Exceptions; /** * Class LogNotFoundException * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogNotFoundException extends LogViewerException { /** * Make the exception. * * @param string $date * * @return static */ public static function make(string $date) { return new static("Log not found in this date [{$date}]"); } } log-viewer/src/Exceptions/FilesystemException.php 0000644 00000000753 15002151620 0016245 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Exceptions; /** * Class FilesystemException * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class FilesystemException extends LogViewerException { public static function cannotDeleteLog() { return new static('There was an error deleting the log.'); } public static function invalidPath(string $path) { return new static("The log(s) could not be located at : $path"); } } log-viewer/src/Exceptions/LogViewerException.php 0000644 00000000331 15002151620 0016014 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Exceptions; /** * Class LogViewerException * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogViewerException extends \Exception {} log-viewer/src/LogViewerServiceProvider.php 0000644 00000002765 15002151620 0015065 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer; use Arcanedev\Support\Providers\PackageServiceProvider; /** * Class LogViewerServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogViewerServiceProvider extends PackageServiceProvider { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Package name. * * @var string */ protected $package = 'log-viewer'; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Register the service provider. */ public function register(): void { parent::register(); $this->registerConfig(); $this->registerProvider(Providers\RouteServiceProvider::class); $this->registerCommands([ Commands\PublishCommand::class, Commands\StatsCommand::class, Commands\CheckCommand::class, Commands\ClearCommand::class, ]); } /** * Boot the service provider. */ public function boot(): void { $this->loadTranslations(); $this->loadViews(); if ($this->app->runningInConsole()) { $this->publishConfig(); $this->publishTranslations(); $this->publishViews(); } } } log-viewer/src/Contracts/Utilities/LogChecker.php 0000644 00000003672 15002151620 0016045 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts\Utilities; use Illuminate\Contracts\Config\Repository as ConfigContract; /** * Interface LogChecker * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface LogChecker { /* ----------------------------------------------------------------- | Constants | ----------------------------------------------------------------- */ /** * @link http://laravel.com/docs/5.4/errors#configuration * @link https://github.com/Seldaek/monolog/blob/master/doc/02-handlers-formatters-processors.md#log-to-files-and-syslog */ const HANDLER_DAILY = 'daily'; const HANDLER_SINGLE = 'single'; const HANDLER_SYSLOG = 'syslog'; const HANDLER_ERRORLOG = 'errorlog'; /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the config instance. * * @param \Illuminate\Contracts\Config\Repository $config * * @return self */ public function setConfig(ConfigContract $config); /** * Set the Filesystem instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * * @return self */ public function setFilesystem(Filesystem $filesystem); /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get messages. * * @return array */ public function messages(); /** * Check passes ?? * * @return bool */ public function passes(); /** * Check fails ?? * * @return bool */ public function fails(); /** * Get the requirements * * @return array */ public function requirements(); } log-viewer/src/Contracts/Utilities/Filesystem.php 0000644 00000005400 15002151620 0016152 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts\Utilities; use Arcanedev\LogViewer\Contracts\Patternable; /** * Interface Filesystem * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface Filesystem extends Patternable { /* ----------------------------------------------------------------- | Constants | ----------------------------------------------------------------- */ const PATTERN_PREFIX = 'laravel-'; const PATTERN_DATE = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'; const PATTERN_EXTENSION = '.log'; /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the files instance. * * @return \Illuminate\Filesystem\Filesystem */ public function getInstance(); /** * Set the log storage path. * * @param string $storagePath * * @return $this */ public function setPath($storagePath); /** * Set the log date pattern. * * @param string $datePattern * * @return $this */ public function setDatePattern($datePattern); /** * Set the log prefix pattern. * * @param string $prefixPattern * * @return $this */ public function setPrefixPattern($prefixPattern); /** * Set the log extension. * * @param string $extension * * @return $this */ public function setExtension($extension); /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get all log files. * * @return array */ public function all(); /** * Get all valid log files. * * @return array */ public function logs(); /** * List the log files (Only dates). * * @param bool $withPaths * * @return array */ public function dates($withPaths = false); /** * Read the log. * * @param string $date * * @return string * * @throws \Arcanedev\LogViewer\Exceptions\FilesystemException */ public function read($date); /** * Delete the log. * * @param string $date * * @return bool * * @throws \Arcanedev\LogViewer\Exceptions\FilesystemException */ public function delete(string $date); /** * Clear the log files. * * @return bool */ public function clear(); /** * Get the log file path. * * @param string $date * * @return string */ public function path($date); } log-viewer/src/Contracts/Utilities/LogMenu.php 0000644 00000002427 15002151620 0015402 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts\Utilities; use Arcanedev\LogViewer\Entities\Log; use Illuminate\Contracts\Config\Repository as ConfigContract; /** * Interface LogMenu * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface LogMenu { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the config instance. * * @param \Illuminate\Contracts\Config\Repository $config * * @return self */ public function setConfig(ConfigContract $config); /** * Set the log styler instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\LogStyler $styler * * @return self */ public function setLogStyler(LogStyler $styler); /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Make log menu. * * @param \Arcanedev\LogViewer\Entities\Log $log * @param bool $trans * * @return array */ public function make(Log $log, $trans = true); } log-viewer/src/Contracts/Utilities/LogStyler.php 0000644 00000001706 15002151620 0015757 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts\Utilities; /** * Interface LogStyler * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface LogStyler { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Make level icon. * * @param string $level * @param string|null $default * * @return \Illuminate\Support\HtmlString */ public function icon($level, $default = null); /** * Get level color. * * @param string $level * @param string|null $default * * @return string */ public function color($level, $default = null); /** * Get strings to highlight. * * @param array $default * * @return array */ public function toHighlight(array $default = []); } log-viewer/src/Contracts/Utilities/Factory.php 0000644 00000007424 15002151620 0015445 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts\Utilities; use Arcanedev\LogViewer\Contracts\Patternable; /** * Interface Factory * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface Factory extends Patternable { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the filesystem instance. * * @return \Arcanedev\LogViewer\Contracts\Utilities\Filesystem */ public function getFilesystem(); /** * Set the filesystem instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * * @return self */ public function setFilesystem(Filesystem $filesystem); /** * Get the log levels instance. * * @return \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels */ public function getLevels(); /** * Set the log levels instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels * * @return self */ public function setLevels(LogLevels $levels); /** * Set the log storage path. * * @param string $storagePath * * @return self */ public function setPath($storagePath); /** * Get all logs. * * @return \Arcanedev\LogViewer\Entities\LogCollection */ public function logs(); /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get all logs (alias). * * @see logs * * @return \Arcanedev\LogViewer\Entities\LogCollection */ public function all(); /** * Paginate all logs. * * @param int $perPage * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 30); /** * Get a log by date. * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function log($date); /** * Get a log by date (alias). * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function get($date); /** * Get log entries. * * @param string $date * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function entries($date, $level = 'all'); /** * List the log files (dates). * * @return array */ public function dates(); /** * Get logs count. * * @return int */ public function count(); /** * Get total log entries. * * @param string $level * * @return int */ public function total($level = 'all'); /** * Get tree menu. * * @param bool $trans * * @return array */ public function tree($trans = false); /** * Get tree menu. * * @param bool $trans * * @return array */ public function menu($trans = true); /** * Get logs statistics. * * @return array */ public function stats(); /** * Get logs statistics table. * * @param string|null $locale * * @return \Arcanedev\LogViewer\Tables\StatsTable */ public function statsTable($locale = null); /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Determine if the log folder is empty or not. * * @return bool */ public function isEmpty(); } log-viewer/src/Contracts/Utilities/LogLevels.php 0000644 00000003302 15002151620 0015721 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts\Utilities; use Illuminate\Translation\Translator; /** * Interface LogLevels * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface LogLevels { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the Translator instance. * * @param \Illuminate\Translation\Translator $translator * * @return self */ public function setTranslator(Translator $translator); /** * Get the selected locale. * * @return string */ public function getLocale(); /** * Set the selected locale. * * @param string $locale * * @return self */ public function setLocale($locale); /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get the log levels. * * @param bool $flip * * @return array */ public function lists($flip = false); /** * Get translated levels. * * @param string|null $locale * * @return array */ public function names($locale = null); /** * Get PSR log levels. * * @param bool $flip * * @return array */ public static function all($flip = false); /** * Get the translated level. * * @param string $key * @param string|null $locale * * @return string */ public function get($key, $locale = null); } log-viewer/src/Contracts/Table.php 0000644 00000001216 15002151620 0013103 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts; /** * Interface Table * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface Table { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get table header. * * @return array */ public function header(); /** * Get table rows. * * @return array */ public function rows(); /** * Get table footer. * * @return array */ public function footer(); } log-viewer/src/Contracts/Patternable.php 0000644 00000001576 15002151620 0014326 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem; /** * Interface Patternable * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface Patternable { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the log pattern. * * @return string */ public function getPattern(); /** * Set the log pattern. * * @param string $date * @param string $prefix * @param string $extension * * @return self */ public function setPattern( $prefix = Filesystem::PATTERN_PREFIX, $date = Filesystem::PATTERN_DATE, $extension = Filesystem::PATTERN_EXTENSION ); } log-viewer/src/Contracts/LogViewer.php 0000644 00000007756 15002151620 0013776 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Contracts; /** * Interface LogViewer * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ interface LogViewer extends Patternable { /* ----------------------------------------------------------------- | Getters & Methods | ----------------------------------------------------------------- */ /** * Get the log levels. * * @param bool|false $flip * * @return array */ public function levels($flip = false); /** * Get the translated log levels. * * @param string|null $locale * * @return array */ public function levelsNames($locale = null); /** * Set the log storage path. * * @param string $path * * @return self */ public function setPath($path); /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get all logs. * * @return \Arcanedev\LogViewer\Entities\LogCollection|\Arcanedev\LogViewer\Entities\Log[] */ public function all(); /** * Paginate all logs. * * @param int $perPage * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 30); /** * Get a log. * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function get($date); /** * Get the log entries. * * @param string $date * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function entries($date, $level = 'all'); /** * Download a log file. * * @param string $date * @param string|null $filename * @param array $headers * * @return \Symfony\Component\HttpFoundation\BinaryFileResponse */ public function download($date, $filename = null, $headers = []); /** * Get logs statistics. * * @return array */ public function stats(); /** * Get logs statistics table. * * @param string|null $locale * * @return \Arcanedev\LogViewer\Tables\StatsTable */ public function statsTable($locale = null); /** * Delete the log. * * @param string $date * * @return bool * * @throws \Arcanedev\LogViewer\Exceptions\FilesystemException */ public function delete($date); /** * Clear the log files. * * @return bool */ public function clear(); /** * List the log files. * * @return array */ public function files(); /** * List the log files (only dates). * * @return array */ public function dates(); /** * Get logs count. * * @return int */ public function count(); /** * Get entries total from all logs. * * @param string $level * * @return int */ public function total($level = 'all'); /** * Get logs tree. * * @param bool|false $trans * * @return array */ public function tree($trans = false); /** * Get logs menu. * * @param bool|true $trans * * @return array */ public function menu($trans = true); /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Determine if the log folder is empty or not. * * @return bool */ public function isEmpty(); /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get the LogViewer version. * * @return string */ public function version(); } log-viewer/src/Commands/CheckCommand.php 0000644 00000005163 15002151620 0014176 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Commands; use Arcanedev\LogViewer\Contracts\Utilities\LogChecker as LogCheckerContract; /** * Class CheckCommand * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class CheckCommand extends Command { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The console command name. * * @var string */ protected $name = 'log-viewer:check'; /** * The console command description. * * @var string */ protected $description = 'Check all LogViewer requirements.'; /** * The name and signature of the console command. * * @var string */ protected $signature = 'log-viewer:check'; /* ----------------------------------------------------------------- | Getter & Setters | ----------------------------------------------------------------- */ /** * Get the Log Checker instance. * * @return \Arcanedev\LogViewer\Contracts\Utilities\LogChecker */ protected function getChecker() { return $this->laravel[LogCheckerContract::class]; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Execute the console command. */ public function handle(): int { $this->displayLogViewer(); $this->displayRequirements(); $this->displayMessages(); return static::SUCCESS; } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Display LogViewer requirements. */ private function displayRequirements() { $requirements = $this->getChecker()->requirements(); $this->frame('Application requirements'); $this->table([ 'Status', 'Message' ], [ [$requirements['status'], $requirements['message']] ]); } /** * Display LogViewer messages. */ private function displayMessages() { $messages = $this->getChecker()->messages(); $rows = []; foreach ($messages['files'] as $file => $message) { $rows[] = [$file, $message]; } if ( ! empty($rows)) { $this->frame('LogViewer messages'); $this->table(['File', 'Message'], $rows); } } } log-viewer/src/Commands/StatsCommand.php 0000644 00000003647 15002151620 0014264 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Commands; use Arcanedev\LogViewer\Tables\StatsTable; /** * Class StatsCommand * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class StatsCommand extends Command { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The console command name. * * @var string */ protected $name = 'log-viewer:stats'; /** * The console command description. * * @var string */ protected $description = 'Display stats of all logs.'; /** * The name and signature of the console command. * * @var string */ protected $signature = 'log-viewer:stats'; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Execute the console command. */ public function handle() { // Load Data $stats = $this->logViewer->statsTable('en'); $rows = $stats->rows(); $rows[] = $this->tableSeparator(); $rows[] = $this->prepareFooter($stats); // Display Data $this->displayLogViewer(); $this->table($stats->header(), $rows); return static::SUCCESS; } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Prepare footer. * * @param \Arcanedev\LogViewer\Tables\StatsTable $stats * * @return array */ private function prepareFooter(StatsTable $stats) { $files = [ 'count' => count($stats->rows()).' log file(s)' ]; return $files + $stats->footer(); } } log-viewer/src/Commands/ClearCommand.php 0000644 00000002225 15002151620 0014203 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Commands; /** * Class ClearCommand * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class ClearCommand extends Command { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The name and signature of the console command. * * @var string */ protected $signature = 'log-viewer:clear'; /** * The console command description. * * @var string */ protected $description = 'Clear all generated log files'; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Execute the console command. */ public function handle(): int { if ($this->confirm('This will delete all the log files, Do you wish to continue?')) { $this->logViewer->clear(); $this->info('Successfully cleared the logs!'); } return static::SUCCESS; } } log-viewer/src/Commands/Command.php 0000644 00000003666 15002151620 0013246 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Commands; use Arcanedev\LogViewer\Contracts\LogViewer as LogViewerContract; use Arcanedev\Support\Console\Command as BaseCommand; /** * Class Command * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class Command extends BaseCommand { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** @var \Arcanedev\LogViewer\Contracts\LogViewer */ protected $logViewer; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create the command instance. * * @param \Arcanedev\LogViewer\Contracts\LogViewer $logViewer */ public function __construct(LogViewerContract $logViewer) { parent::__construct(); $this->logViewer = $logViewer; } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Display LogViewer Logo and Copyrights. */ protected function displayLogViewer() { // LOGO $this->comment(' __ _ '); $this->comment(' / / ___ __ _/\ /(_) _____ _____ _ __ '); $this->comment(' / / / _ \ / _` \ \ / / |/ _ \ \ /\ / / _ \ \'__|'); $this->comment('/ /__| (_) | (_| |\ V /| | __/\ V V / __/ | '); $this->comment('\____/\___/ \__, | \_/ |_|\___| \_/\_/ \___|_| '); $this->comment(' |___/ '); $this->line(''); // Copyright $this->comment('Version '.$this->logViewer->version().' - Created by ARCANEDEV'.chr(169)); $this->line(''); } } log-viewer/src/Commands/PublishCommand.php 0000644 00000004035 15002151620 0014564 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Commands; use Arcanedev\LogViewer\LogViewerServiceProvider; use Symfony\Component\Console\Input\InputOption; /** * Class PublishCommand * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class PublishCommand extends Command { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The console command name. * * @var string */ protected $name = 'log-viewer:publish'; /** * The console command description. * * @var string */ protected $description = 'Publish all LogViewer resources and config files'; /** * The name and signature of the console command. * * @var string */ protected $signature = 'log-viewer:publish {--tag= : One or many tags that have assets you want to publish.} {--force : Overwrite any existing files.}'; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Execute the console command. */ public function handle(): int { $args = [ '--provider' => LogViewerServiceProvider::class, ]; if ((bool) $this->option('force')) { $args['--force'] = true; } $args['--tag'] = [$this->option('tag')]; $this->displayLogViewer(); $this->call('vendor:publish', $args); return static::SUCCESS; } /** * Get the console command options. * * @return array * * @codeCoverageIgnore */ protected function getOptions() { return [ ['tag', 't', InputOption::VALUE_OPTIONAL, 'One or many tags that have assets you want to publish.', ''], ['force', 'f', InputOption::VALUE_OPTIONAL, 'Overwrite any existing files.', false], ]; } } log-viewer/src/Providers/RouteServiceProvider.php 0000644 00000003125 15002151620 0016224 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Providers; use Arcanedev\LogViewer\Http\Routes\LogViewerRoute; use Arcanedev\Support\Providers\RouteServiceProvider as ServiceProvider; /** * Class RouteServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class RouteServiceProvider extends ServiceProvider { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Check if routes is enabled * * @return bool */ public function isEnabled(): bool { return (bool) $this->config('enabled', false); } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Boot the service provider. */ public function boot(): void { if ($this->isEnabled()) { $this->routes(function () { static::mapRouteClasses([LogViewerRoute::class]); }); } } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get config value by key * * @param string $key * @param mixed|null $default * * @return mixed */ private function config($key, $default = null) { return $this->app['config']->get("log-viewer.route.$key", $default); } } log-viewer/src/Providers/DeferredServicesProvider.php 0000644 00000010053 15002151620 0017027 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Providers; use Arcanedev\LogViewer\Contracts\LogViewer as LogViewerContract; use Arcanedev\LogViewer\Contracts\Utilities\Factory as FactoryContract; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem as FilesystemContract; use Arcanedev\LogViewer\Contracts\Utilities\LogChecker as LogCheckerContract; use Arcanedev\LogViewer\Contracts\Utilities\LogLevels as LogLevelsContract; use Arcanedev\LogViewer\Contracts\Utilities\LogMenu as LogMenuContract; use Arcanedev\LogViewer\Contracts\Utilities\LogStyler as LogStylerContract; use Arcanedev\LogViewer\LogViewer; use Arcanedev\LogViewer\Utilities; use Arcanedev\Support\Providers\ServiceProvider; use Illuminate\Contracts\Support\DeferrableProvider; /** * Class DeferredServicesProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class DeferredServicesProvider extends ServiceProvider implements DeferrableProvider { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Register the service provider. */ public function register(): void { $this->registerLogViewer(); $this->registerLogLevels(); $this->registerStyler(); $this->registerLogMenu(); $this->registerFilesystem(); $this->registerFactory(); $this->registerChecker(); } /** * Get the services provided by the provider. * * @return array */ public function provides(): array { return [ LogViewerContract::class, LogLevelsContract::class, LogStylerContract::class, LogMenuContract::class, FilesystemContract::class, FactoryContract::class, LogCheckerContract::class, ]; } /* ----------------------------------------------------------------- | LogViewer Utilities | ----------------------------------------------------------------- */ /** * Register the log viewer service. */ private function registerLogViewer(): void { $this->singleton(LogViewerContract::class, LogViewer::class); } /** * Register the log levels. */ private function registerLogLevels(): void { $this->singleton(LogLevelsContract::class, function ($app) { return new Utilities\LogLevels( $app['translator'], $app['config']->get('log-viewer.locale') ); }); } /** * Register the log styler. */ private function registerStyler(): void { $this->singleton(LogStylerContract::class, Utilities\LogStyler::class); } /** * Register the log menu builder. */ private function registerLogMenu(): void { $this->singleton(LogMenuContract::class, Utilities\LogMenu::class); } /** * Register the log filesystem. */ private function registerFilesystem(): void { $this->singleton(FilesystemContract::class, function ($app) { /** @var \Illuminate\Config\Repository $config */ $config = $app['config']; $filesystem = new Utilities\Filesystem($app['files'], $config->get('log-viewer.storage-path')); return $filesystem->setPattern( $config->get('log-viewer.pattern.prefix', FilesystemContract::PATTERN_PREFIX), $config->get('log-viewer.pattern.date', FilesystemContract::PATTERN_DATE), $config->get('log-viewer.pattern.extension', FilesystemContract::PATTERN_EXTENSION) ); }); } /** * Register the log factory class. */ private function registerFactory(): void { $this->singleton(FactoryContract::class, Utilities\Factory::class); } /** * Register the log checker service. */ private function registerChecker(): void { $this->singleton(LogCheckerContract::class, Utilities\LogChecker::class); } } log-viewer/src/Entities/LogCollection.php 0000644 00000011664 15002151620 0014445 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Entities; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem as FilesystemContract; use Arcanedev\LogViewer\Exceptions\LogNotFoundException; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\LazyCollection; /** * Class LogCollection * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogCollection extends LazyCollection { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** @var \Arcanedev\LogViewer\Contracts\Utilities\Filesystem */ private $filesystem; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * LogCollection constructor. * * @param mixed $source */ public function __construct($source = null) { $this->setFilesystem(app(FilesystemContract::class)); if (is_null($source)) $source = function () { foreach($this->filesystem->dates(true) as $date => $path) { yield $date => Log::make($date, $path, $this->filesystem->read($date)); } }; parent::__construct($source); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the filesystem instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * * @return \Arcanedev\LogViewer\Entities\LogCollection */ public function setFilesystem(FilesystemContract $filesystem) { $this->filesystem = $filesystem; return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get a log. * * @param string $date * @param mixed|null $default * * @return \Arcanedev\LogViewer\Entities\Log * * @throws \Arcanedev\LogViewer\Exceptions\LogNotFoundException */ public function get($date, $default = null) { if ( ! $this->has($date)) throw LogNotFoundException::make($date); return parent::get($date, $default); } /** * Paginate logs. * * @param int $perPage * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 30) { $page = request()->get('page', 1); $path = request()->url(); return new LengthAwarePaginator( $this->forPage($page, $perPage), $this->count(), $perPage, $page, compact('path') ); } /** * Get a log (alias). * * @see get() * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function log($date) { return $this->get($date); } /** * Get log entries. * * @param string $date * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function entries($date, $level = 'all') { return $this->get($date)->entries($level); } /** * Get logs statistics. * * @return array */ public function stats() { $stats = []; foreach ($this->all() as $date => $log) { /** @var \Arcanedev\LogViewer\Entities\Log $log */ $stats[$date] = $log->stats(); } return $stats; } /** * List the log files (dates). * * @return array */ public function dates() { return $this->keys()->toArray(); } /** * Get entries total. * * @param string $level * * @return int */ public function total($level = 'all') { return (int) $this->sum(function (Log $log) use ($level) { return $log->entries($level)->count(); }); } /** * Get logs tree. * * @param bool $trans * * @return array */ public function tree($trans = false) { $tree = []; foreach ($this->all() as $date => $log) { /** @var \Arcanedev\LogViewer\Entities\Log $log */ $tree[$date] = $log->tree($trans); } return $tree; } /** * Get logs menu. * * @param bool $trans * * @return array */ public function menu($trans = true) { $menu = []; foreach ($this->all() as $date => $log) { /** @var \Arcanedev\LogViewer\Entities\Log $log */ $menu[$date] = $log->menu($trans); } return $menu; } } log-viewer/src/Entities/LogEntry.php 0000644 00000015626 15002151620 0013455 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Entities; use Arcanedev\LogViewer\Helpers\LogParser; use Carbon\Carbon; use Illuminate\Contracts\Support\{Arrayable, Jsonable}; use JsonSerializable; /** * Class LogEntry * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogEntry implements Arrayable, Jsonable, JsonSerializable { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** @var string */ public $env; /** @var string */ public $level; /** @var \Carbon\Carbon */ public $datetime; /** @var string */ public $header; /** @var string */ public $stack; /** @var array */ public $context = []; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Construct the log entry instance. * * @param string $level * @param string $header * @param string|null $stack */ public function __construct($level, $header, $stack = null) { $this->setLevel($level); $this->setHeader($header); $this->setStack($stack); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the entry level. * * @param string $level * * @return self */ private function setLevel($level) { $this->level = $level; return $this; } /** * Set the entry header. * * @param string $header * * @return self */ private function setHeader($header) { $this->setDatetime($this->extractDatetime($header)); $header = $this->cleanHeader($header); $this->header = trim($header); return $this; } /** * Set the context. * * @param array $context * * @return $this */ private function setContext(array $context) { $this->context = $context; return $this; } /** * Set entry environment. * * @param string $env * * @return self */ private function setEnv($env) { $this->env = head(explode('.', $env)); return $this; } /** * Set the entry date time. * * @param string $datetime * * @return \Arcanedev\LogViewer\Entities\LogEntry */ private function setDatetime($datetime) { $this->datetime = Carbon::createFromFormat('Y-m-d H:i:s', $datetime); return $this; } /** * Set the entry stack. * * @param string $stack * * @return self */ private function setStack($stack) { $this->stack = $stack; return $this; } /** * Get translated level name with icon. * * @return string */ public function level() { return $this->icon()->toHtml().' '.$this->name(); } /** * Get translated level name. * * @return string */ public function name() { return log_levels()->get($this->level); } /** * Get level icon. * * @return \Illuminate\Support\HtmlString */ public function icon() { return log_styler()->icon($this->level); } /** * Get the entry stack. * * @return string */ public function stack() { return trim(htmlentities($this->stack)); } /** * Get the entry context as json pretty print. */ public function context(int $options = JSON_PRETTY_PRINT): string { return json_encode($this->context, $options); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Check if same log level. * * @param string $level * * @return bool */ public function isSameLevel($level) { return $this->level === $level; } /* ----------------------------------------------------------------- | Convert Methods | ----------------------------------------------------------------- */ /** * Get the log entry as an array. * * @return array */ public function toArray() { return [ 'level' => $this->level, 'datetime' => $this->datetime->format('Y-m-d H:i:s'), 'header' => $this->header, 'stack' => $this->stack ]; } /** * Convert the log entry to its JSON representation. * * @param int $options * * @return string */ public function toJson($options = 0) { return json_encode($this->toArray(), $options); } /** * Serialize the log entry object to json data. */ public function jsonSerialize(): array { return $this->toArray(); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Check if the entry has a stack. * * @return bool */ public function hasStack() { return $this->stack !== "\n"; } /** * Check if the entry has a context. * * @return bool */ public function hasContext() { return ! empty($this->context); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Clean the entry header. * * @param string $header * * @return string */ private function cleanHeader($header) { // REMOVE THE DATE $header = preg_replace('/\['.LogParser::REGEX_DATETIME_PATTERN.'\][ ]/', '', $header); // EXTRACT ENV if (preg_match('/^[a-z]+.[A-Z]+:/', $header, $out)) { $this->setEnv($out[0]); $header = trim(str_replace($out[0], '', $header)); } // EXTRACT CONTEXT (Regex from https://stackoverflow.com/a/21995025) preg_match_all('/{(?:[^{}]|(?R))*}/x', $header, $out); if (isset($out[0][0]) && ! is_null($context = json_decode($out[0][0], true))) { $header = str_replace($out[0][0], '', $header); $this->setContext($context); } return $header; } /** * Extract datetime from the header. * * @param string $header * * @return string */ private function extractDatetime($header) { return preg_replace('/^\[('.LogParser::REGEX_DATETIME_PATTERN.')\].*/', '$1', $header); } } log-viewer/src/Entities/LogEntryCollection.php 0000644 00000005773 15002151620 0015473 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Entities; use Arcanedev\LogViewer\Helpers\LogParser; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\LazyCollection; /** * Class LogEntryCollection * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogEntryCollection extends LazyCollection { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Load raw log entries. * * @param string $raw * * @return self */ public static function load($raw) { return new static(function () use ($raw) { foreach (LogParser::parse($raw) as $entry) { list($level, $header, $stack) = array_values($entry); yield new LogEntry($level, $header, $stack); } }); } /** * Paginate log entries. * * @param int $perPage * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 20) { $page = request()->get('page', 1); $path = request()->url(); return new LengthAwarePaginator( $this->forPage($page, $perPage), $this->count(), $perPage, $page, compact('path') ); } /** * Get filtered log entries by level. * * @param string $level * * @return self */ public function filterByLevel($level) { return $this->filter(function(LogEntry $entry) use ($level) { return $entry->isSameLevel($level); }); } /** * Get log entries stats. * * @return array */ public function stats() { $counters = $this->initStats(); foreach ($this->groupBy('level') as $level => $entries) { $counters[$level] = $count = count($entries); $counters['all'] += $count; } return $counters; } /** * Get the log entries navigation tree. * * @param bool|false $trans * * @return array */ public function tree($trans = false) { $tree = $this->stats(); array_walk($tree, function(&$count, $level) use ($trans) { $count = [ 'name' => $trans ? log_levels()->get($level) : $level, 'count' => $count, ]; }); return $tree; } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Init stats counters. * * @return array */ private function initStats() { $levels = array_merge_recursive( ['all'], array_keys(log_viewer()->levels(true)) ); return array_map(function () { return 0; }, array_flip($levels)); } } log-viewer/src/Entities/Log.php 0000644 00000012504 15002151620 0012423 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Entities; use Illuminate\Contracts\Support\{Arrayable, Jsonable}; use Illuminate\Support\Carbon; use JsonSerializable; use SplFileInfo; /** * Class Log * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class Log implements Arrayable, Jsonable, JsonSerializable { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** @var string */ public $date; /** @var string */ private $path; /** @var \Arcanedev\LogViewer\Entities\LogEntryCollection */ private $entries; /** @var \SplFileInfo */ private $file; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Log constructor. * * @param string $date * @param string $path * @param string $raw */ public function __construct($date, $path, $raw) { $this->date = $date; $this->path = $path; $this->file = new SplFileInfo($path); $this->entries = LogEntryCollection::load($raw); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get log path. * * @return string */ public function getPath() { return $this->path; } /** * Get file info. * * @return \SplFileInfo */ public function file() { return $this->file; } /** * Get file size. * * @return string */ public function size() { return $this->formatSize($this->file->getSize()); } /** * Get file creation date. * * @return \Carbon\Carbon */ public function createdAt() { return Carbon::createFromTimestamp($this->file()->getATime()); } /** * Get file modification date. * * @return \Carbon\Carbon */ public function updatedAt() { return Carbon::createFromTimestamp($this->file()->getMTime()); } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Make a log object. * * @param string $date * @param string $path * @param string $raw * * @return self */ public static function make($date, $path, $raw) { return new self($date, $path, $raw); } /** * Get log entries. * * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function entries($level = 'all') { return $level === 'all' ? $this->entries : $this->getByLevel($level); } /** * Get filtered log entries by level. * * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function getByLevel($level) { return $this->entries->filterByLevel($level); } /** * Get log stats. * * @return array */ public function stats() { return $this->entries->stats(); } /** * Get the log navigation tree. * * @param bool $trans * * @return array */ public function tree($trans = false) { return $this->entries->tree($trans); } /** * Get log entries menu. * * @param bool $trans * * @return array */ public function menu($trans = true) { return log_menu()->make($this, $trans); } /* ----------------------------------------------------------------- | Convert Methods | ----------------------------------------------------------------- */ /** * Get the log as a plain array. * * @return array */ public function toArray() { return [ 'date' => $this->date, 'path' => $this->path, 'entries' => $this->entries->toArray() ]; } /** * Convert the object to its JSON representation. * * @param int $options * * @return string */ public function toJson($options = 0) { return json_encode($this->toArray(), $options); } /** * Serialize the log object to json data. * * @return array */ public function jsonSerialize(): array { return $this->toArray(); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Format the file size. * * @param int $bytes * @param int $precision * * @return string */ private function formatSize($bytes, $precision = 2) { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); return round($bytes / pow(1024, $pow), $precision).' '.$units[$pow]; } } log-viewer/src/LogViewer.php 0000644 00000017227 15002151620 0012030 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer; use Arcanedev\LogViewer\Contracts\Utilities\Filesystem as FilesystemContract; use Arcanedev\LogViewer\Contracts\Utilities\Factory as FactoryContract; use Arcanedev\LogViewer\Contracts\Utilities\LogLevels as LogLevelsContract; use Arcanedev\LogViewer\Contracts\LogViewer as LogViewerContract; /** * Class LogViewer * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogViewer implements LogViewerContract { /* ----------------------------------------------------------------- | Constants | ----------------------------------------------------------------- */ /** * LogViewer Version */ const VERSION = '9.0.0'; /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The factory instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\Factory */ protected $factory; /** * The filesystem instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\Filesystem */ protected $filesystem; /** * The log levels instance. * * @var \Arcanedev\LogViewer\Contracts\Utilities\LogLevels */ protected $levels; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create a new instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\Factory $factory * @param \Arcanedev\LogViewer\Contracts\Utilities\Filesystem $filesystem * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels */ public function __construct( FactoryContract $factory, FilesystemContract $filesystem, LogLevelsContract $levels ) { $this->factory = $factory; $this->filesystem = $filesystem; $this->levels = $levels; } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the log levels. * * @param bool $flip * * @return array */ public function levels($flip = false) { return $this->levels->lists($flip); } /** * Get the translated log levels. * * @param string|null $locale * * @return array */ public function levelsNames($locale = null) { return $this->levels->names($locale); } /** * Set the log storage path. * * @param string $path * * @return self */ public function setPath($path) { $this->factory->setPath($path); return $this; } /** * Get the log pattern. * * @return string */ public function getPattern() { return $this->factory->getPattern(); } /** * Set the log pattern. * * @param string $date * @param string $prefix * @param string $extension * * @return self */ public function setPattern( $prefix = FilesystemContract::PATTERN_PREFIX, $date = FilesystemContract::PATTERN_DATE, $extension = FilesystemContract::PATTERN_EXTENSION ) { $this->factory->setPattern($prefix, $date, $extension); return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get all logs. * * @return \Arcanedev\LogViewer\Entities\LogCollection */ public function all() { return $this->factory->all(); } /** * Paginate all logs. * * @param int $perPage * * @return \Illuminate\Pagination\LengthAwarePaginator */ public function paginate($perPage = 30) { return $this->factory->paginate($perPage); } /** * Get a log. * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log */ public function get($date) { return $this->factory->log($date); } /** * Get the log entries. * * @param string $date * @param string $level * * @return \Arcanedev\LogViewer\Entities\LogEntryCollection */ public function entries($date, $level = 'all') { return $this->factory->entries($date, $level); } /** * Download a log file. * * @param string $date * @param string|null $filename * @param array $headers * * @return \Symfony\Component\HttpFoundation\BinaryFileResponse */ public function download($date, $filename = null, $headers = []) { if (is_null($filename)) { $filename = sprintf( "%s{$date}.%s", config('log-viewer.download.prefix', 'laravel-'), config('log-viewer.download.extension', 'log') ); } $path = $this->filesystem->path($date); return response()->download($path, $filename, $headers); } /** * Get logs statistics. * * @return array */ public function stats() { return $this->factory->stats(); } /** * Get logs statistics table. * * @param string|null $locale * * @return \Arcanedev\LogViewer\Tables\StatsTable */ public function statsTable($locale = null) { return $this->factory->statsTable($locale); } /** * Delete the log. * * @param string $date * * @return bool */ public function delete($date) { return $this->filesystem->delete($date); } /** * Clear the log files. * * @return bool */ public function clear() { return $this->filesystem->clear(); } /** * Get all valid log files. * * @return array */ public function files() { return $this->filesystem->logs(); } /** * List the log files (only dates). * * @return array */ public function dates() { return $this->factory->dates(); } /** * Get logs count. * * @return int */ public function count() { return $this->factory->count(); } /** * Get entries total from all logs. * * @param string $level * * @return int */ public function total($level = 'all') { return $this->factory->total($level); } /** * Get logs tree. * * @param bool $trans * * @return array */ public function tree($trans = false) { return $this->factory->tree($trans); } /** * Get logs menu. * * @param bool $trans * * @return array */ public function menu($trans = true) { return $this->factory->menu($trans); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Determine if the log folder is empty or not. * * @return bool */ public function isEmpty() { return $this->factory->isEmpty(); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get the LogViewer version. * * @return string */ public function version() { return self::VERSION; } } log-viewer/src/Helpers/LogParser.php 0000644 00000006652 15002151620 0013425 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Helpers; use Arcanedev\LogViewer\Utilities\LogLevels; use Illuminate\Support\Str; /** * Class LogParser * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogParser { /* ----------------------------------------------------------------- | Constants | ----------------------------------------------------------------- */ const REGEX_DATE_PATTERN = '\d{4}(-\d{2}){2}'; const REGEX_TIME_PATTERN = '\d{2}(:\d{2}){2}'; const REGEX_DATETIME_PATTERN = self::REGEX_DATE_PATTERN.' '.self::REGEX_TIME_PATTERN; /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Parsed data. * * @var array */ protected static $parsed = []; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Parse file content. * * @param string $raw * * @return array */ public static function parse($raw) { static::$parsed = []; list($headings, $data) = static::parseRawData($raw); // @codeCoverageIgnoreStart if ( ! is_array($headings)) { return static::$parsed; } // @codeCoverageIgnoreEnd foreach ($headings as $heading) { for ($i = 0, $j = count($heading); $i < $j; $i++) { static::populateEntries($heading, $data, $i); } }; unset($headings, $data); return array_reverse(static::$parsed); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Extract the date. * * @param string $string * * @return string */ public static function extractDate(string $string): string { return preg_replace('/.*('.self::REGEX_DATE_PATTERN.').*/', '$1', $string); } /** * Parse raw data. * * @param string $raw * * @return array */ private static function parseRawData($raw) { $pattern = '/\['.self::REGEX_DATETIME_PATTERN.'\].*/'; preg_match_all($pattern, $raw, $headings); $data = preg_split($pattern, $raw); if ($data[0] < 1) { $trash = array_shift($data); unset($trash); } return [$headings, $data]; } /** * Populate entries. * * @param array $heading * @param array $data * @param int $key */ private static function populateEntries($heading, $data, $key) { foreach (LogLevels::all() as $level) { if (static::hasLogLevel($heading[$key], $level)) { static::$parsed[] = [ 'level' => $level, 'header' => $heading[$key], 'stack' => $data[$key] ]; } } } /** * Check if header has a log level. * * @param string $heading * @param string $level * * @return bool */ private static function hasLogLevel($heading, $level) { return Str::contains($heading, strtoupper(".{$level}:")); } } log-viewer/src/Tables/StatsTable.php 0000644 00000006150 15002151620 0013376 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Tables; use Arcanedev\LogViewer\Contracts\Utilities\LogLevels as LogLevelsContract; use Illuminate\Support\{Arr, Collection}; /** * Class StatsTable * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class StatsTable extends AbstractTable { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Make a stats table instance. * * @param array $data * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels * @param string|null $locale * * @return $this */ public static function make(array $data, LogLevelsContract $levels, $locale = null) { return new static($data, $levels, $locale); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Prepare table header. * * @param array $data * * @return array */ protected function prepareHeader(array $data) { return array_merge_recursive( [ 'date' => __('Date'), 'all' => __('All'), ], $this->levels->names($this->locale) ); } /** * Prepare table rows. * * @param array $data * * @return array */ protected function prepareRows(array $data) { $rows = []; foreach ($data as $date => $levels) { $rows[$date] = array_merge(compact('date'), $levels); } return $rows; } /** * Prepare table footer. * * @param array $data * * @return array */ protected function prepareFooter(array $data) { $footer = []; foreach ($data as $date => $levels) { foreach ($levels as $level => $count) { if ( ! isset($footer[$level])) { $footer[$level] = 0; } $footer[$level] += $count; } } return $footer; } /** * Get totals. * * @param string|null $locale * * @return \Illuminate\Support\Collection */ public function totals($locale = null) { $totals = Collection::make(); foreach (Arr::except($this->footer(), 'all') as $level => $count) { $totals->put($level, [ 'label' => log_levels()->get($level, $locale), 'value' => $count, 'color' => $this->color($level), 'highlight' => $this->color($level), ]); } return $totals; } /** * Get json totals data. * * @param string|null $locale * * @return string */ public function totalsJson($locale = null) { return $this->totals($locale)->toJson(JSON_PRETTY_PRINT); } } log-viewer/src/Tables/AbstractTable.php 0000644 00000010567 15002151620 0014052 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Tables; use Arcanedev\LogViewer\Contracts\Table as TableContract; use Arcanedev\LogViewer\Contracts\Utilities\LogLevels as LogLevelsContract; /** * Class AbstractTable * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class AbstractTable implements TableContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** @var array */ private $header = []; /** @var array */ private $rows = []; /** @var array */ private $footer = []; /** @var \Arcanedev\LogViewer\Contracts\Utilities\LogLevels */ protected $levels; /** @var string|null */ protected $locale; /** @var array */ private $data = []; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create a table instance. * * @param array $data * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels * @param string|null $locale */ public function __construct(array $data, LogLevelsContract $levels, $locale = null) { $this->setLevels($levels); $this->setLocale(is_null($locale) ? config('log-viewer.locale') : $locale); $this->setData($data); $this->init(); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set LogLevels instance. * * @param \Arcanedev\LogViewer\Contracts\Utilities\LogLevels $levels * * @return $this */ protected function setLevels(LogLevelsContract $levels) { $this->levels = $levels; return $this; } /** * Set table locale. * * @param string|null $locale * * @return $this */ protected function setLocale($locale) { if (is_null($locale) || $locale === 'auto') { $locale = app()->getLocale(); } $this->locale = $locale; return $this; } /** * Get table header. * * @return array */ public function header() { return $this->header; } /** * Get table rows. * * @return array */ public function rows() { return $this->rows; } /** * Get table footer. * * @return array */ public function footer() { return $this->footer; } /** * Get raw data. * * @return array */ public function data() { return $this->data; } /** * Set table data. * * @param array $data * * @return $this */ private function setData(array $data) { $this->data = $data; return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Prepare the table. */ private function init() { $this->header = $this->prepareHeader($this->data); $this->rows = $this->prepareRows($this->data); $this->footer = $this->prepareFooter($this->data); } /** * Prepare table header. * * @param array $data * * @return array */ abstract protected function prepareHeader(array $data); /** * Prepare table rows. * * @param array $data * * @return array */ abstract protected function prepareRows(array $data); /** * Prepare table footer. * * @param array $data * * @return array */ abstract protected function prepareFooter(array $data); /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get log level color. * * @param string $level * * @return string */ protected function color($level) { return log_styler()->color($level); } } log-viewer/src/Http/Controllers/LogViewerController.php 0000644 00000021172 15002151620 0017313 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Http\Controllers; use Arcanedev\LogViewer\Contracts\LogViewer as LogViewerContract; use Arcanedev\LogViewer\Entities\{LogEntry, LogEntryCollection}; use Arcanedev\LogViewer\Exceptions\LogNotFoundException; use Arcanedev\LogViewer\Tables\StatsTable; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Routing\Controller; use Illuminate\Support\{Arr, Collection, Str}; /** * Class LogViewerController * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogViewerController extends Controller { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The log viewer instance * * @var \Arcanedev\LogViewer\Contracts\LogViewer */ protected $logViewer; /** @var int */ protected $perPage = 30; /** @var string */ protected $showRoute = 'log-viewer::logs.show'; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * LogViewerController constructor. * * @param \Arcanedev\LogViewer\Contracts\LogViewer $logViewer */ public function __construct(LogViewerContract $logViewer) { $this->logViewer = $logViewer; $this->perPage = config('log-viewer.per-page', $this->perPage); } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Show the dashboard. * * @return \Illuminate\View\View */ public function index() { $stats = $this->logViewer->statsTable(); $chartData = $this->prepareChartData($stats); $percents = $this->calcPercentages($stats->footer(), $stats->header()); return $this->view('dashboard', compact('chartData', 'percents')); } /** * List all logs. * * @param \Illuminate\Http\Request $request * * @return \Illuminate\View\View */ public function listLogs(Request $request) { $stats = $this->logViewer->statsTable(); $headers = $stats->header(); $rows = $this->paginate($stats->rows(), $request); return $this->view('logs', compact('headers', 'rows')); } /** * Show the log. * * @param \Illuminate\Http\Request $request * @param string $date * * @return \Illuminate\View\View */ public function show(Request $request, $date) { $level = 'all'; $log = $this->getLogOrFail($date); $query = $request->get('query'); $levels = $this->logViewer->levelsNames(); $entries = $log->entries($level)->paginate($this->perPage); return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries')); } /** * Filter the log entries by level. * * @param \Illuminate\Http\Request $request * @param string $date * @param string $level * * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse */ public function showByLevel(Request $request, $date, $level) { if ($level === 'all') return redirect()->route($this->showRoute, [$date]); $log = $this->getLogOrFail($date); $query = $request->get('query'); $levels = $this->logViewer->levelsNames(); $entries = $this->logViewer->entries($date, $level)->paginate($this->perPage); return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries')); } /** * Show the log with the search query. * * @param \Illuminate\Http\Request $request * @param string $date * @param string $level * * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse */ public function search(Request $request, $date, $level = 'all') { $query = $request->get('query'); if (is_null($query)) return redirect()->route($this->showRoute, [$date]); $log = $this->getLogOrFail($date); $levels = $this->logViewer->levelsNames(); $needles = array_map(function ($needle) { return Str::lower($needle); }, array_filter(explode(' ', $query))); $entries = $log->entries($level) ->unless(empty($needles), function (LogEntryCollection $entries) use ($needles) { return $entries->filter(function (LogEntry $entry) use ($needles) { foreach ([$entry->header, $entry->stack, $entry->context()] as $subject) { if (Str::containsAll(Str::lower($subject), $needles)) return true; } return false; }); }) ->paginate($this->perPage); return $this->view('show', compact('level', 'log', 'query', 'levels', 'entries')); } /** * Download the log * * @param string $date * * @return \Symfony\Component\HttpFoundation\BinaryFileResponse */ public function download($date) { return $this->logViewer->download($date); } /** * Delete a log. * * @param \Illuminate\Http\Request $request * * @return \Illuminate\Http\JsonResponse */ public function delete(Request $request) { abort_unless($request->ajax(), 405, 'Method Not Allowed'); $date = $request->input('date'); return response()->json([ 'result' => $this->logViewer->delete($date) ? 'success' : 'error' ]); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get the evaluated view contents for the given view. * * @param string $view * @param array $data * @param array $mergeData * * @return \Illuminate\View\View */ protected function view($view, $data = [], $mergeData = []) { $theme = config('log-viewer.theme'); return view()->make("log-viewer::{$theme}.{$view}", $data, $mergeData); } /** * Paginate logs. * * @param array $data * @param \Illuminate\Http\Request $request * * @return \Illuminate\Pagination\LengthAwarePaginator */ protected function paginate(array $data, Request $request) { $data = new Collection($data); $page = $request->get('page', 1); $path = $request->url(); return new LengthAwarePaginator( $data->forPage($page, $this->perPage), $data->count(), $this->perPage, $page, compact('path') ); } /** * Get a log or fail * * @param string $date * * @return \Arcanedev\LogViewer\Entities\Log|null */ protected function getLogOrFail($date) { $log = null; try { $log = $this->logViewer->get($date); } catch (LogNotFoundException $e) { abort(404, $e->getMessage()); } return $log; } /** * Prepare chart data. * * @param \Arcanedev\LogViewer\Tables\StatsTable $stats * * @return string */ protected function prepareChartData(StatsTable $stats) { $totals = $stats->totals()->all(); return json_encode([ 'labels' => Arr::pluck($totals, 'label'), 'datasets' => [ [ 'data' => Arr::pluck($totals, 'value'), 'backgroundColor' => Arr::pluck($totals, 'color'), 'hoverBackgroundColor' => Arr::pluck($totals, 'highlight'), ], ], ]); } /** * Calculate the percentage. * * @param array $total * @param array $names * * @return array */ protected function calcPercentages(array $total, array $names) { $percents = []; $all = Arr::get($total, 'all'); foreach ($total as $level => $count) { $percents[$level] = [ 'name' => $names[$level], 'count' => $count, 'percent' => $all ? round(($count / $all) * 100, 2) : 0, ]; } return $percents; } } log-viewer/src/Http/Routes/LogViewerRoute.php 0000644 00000004027 15002151620 0015241 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\LogViewer\Http\Routes; use Arcanedev\LogViewer\Http\Controllers\LogViewerController; use Arcanedev\Support\Routing\RouteRegistrar; /** * Class LogViewerRoute * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class LogViewerRoute extends RouteRegistrar { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Map all routes. */ public function map(): void { $attributes = (array) config('log-viewer.route.attributes'); $this->group($attributes, function() { $this->name('log-viewer::')->group(function () { $this->get('/', [LogViewerController::class, 'index']) ->name('dashboard'); // log-viewer::dashboard $this->mapLogsRoutes(); }); }); } /** * Map the logs routes. */ private function mapLogsRoutes(): void { $this->prefix('logs')->name('logs.')->group(function() { $this->get('/', [LogViewerController::class, 'listLogs']) ->name('list'); // log-viewer::logs.list $this->delete('delete', [LogViewerController::class, 'delete']) ->name('delete'); // log-viewer::logs.delete $this->prefix('{date}')->group(function() { $this->get('/', [LogViewerController::class, 'show']) ->name('show'); // log-viewer::logs.show $this->get('download', [LogViewerController::class, 'download']) ->name('download'); // log-viewer::logs.download $this->get('{level}', [LogViewerController::class, 'showByLevel']) ->name('filter'); // log-viewer::logs.filter $this->get('{level}/search', [LogViewerController::class, 'search']) ->name('search'); // log-viewer::logs.search }); }); } } log-viewer/LICENSE.md 0000644 00000002113 15002151620 0010215 0 ustar 00 The MIT License (MIT) Copyright (c) ARCANEDEV <arcanedev.maroc@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. log-viewer/config/log-viewer.php 0000644 00000011467 15002151620 0012663 0 ustar 00 <?php use Arcanedev\LogViewer\Contracts\Utilities\Filesystem; return [ /* ----------------------------------------------------------------- | Log files storage path | ----------------------------------------------------------------- */ 'storage-path' => storage_path('logs'), /* ----------------------------------------------------------------- | Log files pattern | ----------------------------------------------------------------- */ 'pattern' => [ 'prefix' => Filesystem::PATTERN_PREFIX, // 'laravel-' 'date' => Filesystem::PATTERN_DATE, // '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]' 'extension' => Filesystem::PATTERN_EXTENSION, // '.log' ], /* ----------------------------------------------------------------- | Locale | ----------------------------------------------------------------- | Supported locales : | 'auto', 'ar', 'bg', 'de', 'en', 'es', 'et', 'fa', 'fr', 'hu', 'hy', 'id', 'it', 'ja', 'ko', 'nl', | 'pl', 'pt-BR', 'ro', 'ru', 'sv', 'th', 'tr', 'zh-TW', 'zh' */ 'locale' => 'auto', /* ----------------------------------------------------------------- | Theme | ----------------------------------------------------------------- | Supported themes : | 'bootstrap-3', 'bootstrap-4' | Make your own theme by adding a folder to the views directory and specifying it here. */ 'theme' => 'bootstrap-4', /* ----------------------------------------------------------------- | Route settings | ----------------------------------------------------------------- */ 'route' => [ 'enabled' => true, 'attributes' => [ 'prefix' => 'log-viewer', 'middleware' => env('ARCANEDEV_LOGVIEWER_MIDDLEWARE') ? explode(',', env('ARCANEDEV_LOGVIEWER_MIDDLEWARE')) : null, ], ], /* ----------------------------------------------------------------- | Log entries per page | ----------------------------------------------------------------- | This defines how many logs & entries are displayed per page. */ 'per-page' => 30, /* ----------------------------------------------------------------- | Download settings | ----------------------------------------------------------------- */ 'download' => [ 'prefix' => 'laravel-', 'extension' => 'log', ], /* ----------------------------------------------------------------- | Menu settings | ----------------------------------------------------------------- */ 'menu' => [ 'filter-route' => 'log-viewer::logs.filter', 'icons-enabled' => true, ], /* ----------------------------------------------------------------- | Icons | ----------------------------------------------------------------- */ 'icons' => [ /** * Font awesome >= 4.3 * http://fontawesome.io/icons/ */ 'all' => 'fa fa-fw fa-list', // http://fontawesome.io/icon/list/ 'emergency' => 'fa fa-fw fa-bug', // http://fontawesome.io/icon/bug/ 'alert' => 'fa fa-fw fa-bullhorn', // http://fontawesome.io/icon/bullhorn/ 'critical' => 'fa fa-fw fa-heartbeat', // http://fontawesome.io/icon/heartbeat/ 'error' => 'fa fa-fw fa-times-circle', // http://fontawesome.io/icon/times-circle/ 'warning' => 'fa fa-fw fa-exclamation-triangle', // http://fontawesome.io/icon/exclamation-triangle/ 'notice' => 'fa fa-fw fa-exclamation-circle', // http://fontawesome.io/icon/exclamation-circle/ 'info' => 'fa fa-fw fa-info-circle', // http://fontawesome.io/icon/info-circle/ 'debug' => 'fa fa-fw fa-life-ring', // http://fontawesome.io/icon/life-ring/ ], /* ----------------------------------------------------------------- | Colors | ----------------------------------------------------------------- */ 'colors' => [ 'levels' => [ 'empty' => '#D1D1D1', 'all' => '#8A8A8A', 'emergency' => '#B71C1C', 'alert' => '#D32F2F', 'critical' => '#F44336', 'error' => '#FF5722', 'warning' => '#FF9100', 'notice' => '#4CAF50', 'info' => '#1976D2', 'debug' => '#90CAF9', ], ], /* ----------------------------------------------------------------- | Strings to highlight in stack trace | ----------------------------------------------------------------- */ 'highlight' => [ '^#\d+', '^Stack trace:', ], ]; support/composer.json 0000644 00000002522 15002151620 0010773 0 ustar 00 { "name": "arcanedev/support", "description": "ARCANEDEV Support Helpers", "keywords": ["arcanedev", "arcanesoft", "support", "laravel"], "homepage": "https://github.com/ARCANEDEV/Support", "authors": [ { "name": "ARCANEDEV", "email": "arcanedev.maroc@gmail.com", "homepage": "https://github.com/arcanedev-maroc" } ], "type": "library", "license": "MIT", "require": { "php": "^8.0.2", "illuminate/contracts": "^9.0", "illuminate/support": "^9.0" }, "require-dev": { "laravel/framework": "^9.0", "orchestra/testbench-core": "^7.0", "phpunit/phpunit": "^9.5.8" }, "autoload": { "psr-4": { "Arcanedev\\Support\\": "src/" }, "files": ["helpers.php"] }, "autoload-dev": { "psr-4": { "Arcanedev\\Support\\Tests\\": "tests/" } }, "scripts": { "test": "phpunit --colors=always", "test:dox": "phpunit --testdox --colors=always", "test:cov": "phpunit --coverage-html coverage" }, "extra": { "branch-alias": { "dev-develop": "10.x-dev" } }, "config": { "sort-packages": true }, "minimum-stability": "dev", "prefer-stable": true } support/helpers.php 0000644 00000001644 15002151620 0010430 0 ustar 00 <?php declare(strict_types=1); if ( ! function_exists('laravel_version')) { /** * Get laravel version or check if the same version * * @param string|null $version * * @return string|bool */ function laravel_version(string $version = null) { $appVersion = app()->version(); if (is_null($version)) { return $appVersion; } return substr($appVersion, 0, strlen($version)) === $version; } } if ( ! function_exists('route_is')) { /** * Check if route(s) is the current route. * * @param array|string $routes * * @return bool */ function route_is($routes): bool { if ( ! is_array($routes)) { $routes = [$routes]; } /** @var Illuminate\Routing\Router $router */ $router = app('router'); return call_user_func_array([$router, 'is'], $routes); } } support/README.md 0000644 00000005370 15002151620 0007534 0 ustar 00 # Support [![Packagist License][badge_license]](LICENSE.md) [![For Laravel 5][badge_laravel]][link-github-repo] [![Github Workflow Status][badge_build]][link-github-status] [![Coverage Status][badge_coverage]][link-scrutinizer] [![Scrutinizer Code Quality][badge_quality]][link-scrutinizer] [![SensioLabs Insight][badge_insight]][link-insight] [![Github Issues][badge_issues]][link-github-issues] [![Packagist][badge_package]][link-packagist] [![Packagist Release][badge_release]][link-packagist] [![Packagist Downloads][badge_downloads]][link-packagist] *By [ARCANEDEV©](http://www.arcanedev.net/)* Support package is a collection of helpers and tools for ARCANEDEV + Laravel projects. Feel free to check out the [releases](https://github.com/ARCANEDEV/Support/releases), [license](LICENSE.md), and [contribution guidelines](CONTRIBUTING.md). ## Contribution Any ideas are welcome. Feel free to submit any issues or pull requests, please check the [contribution guidelines](CONTRIBUTING.md). ## Security If you discover any security related issues, please email arcanedev.maroc@gmail.com instead of using the issue tracker. ## Credits - [ARCANEDEV][link-author] - [All Contributors][link-contributors] [badge_license]: http://img.shields.io/packagist/l/arcanedev/support.svg?style=flat-square [badge_laravel]: https://img.shields.io/badge/Laravel-5.1%20to%209.x-orange.svg?style=flat-square [badge_build]: https://img.shields.io/github/workflow/status/ARCANEDEV/Support/run-tests?style=flat-square [badge_coverage]: https://img.shields.io/scrutinizer/coverage/g/ARCANEDEV/Support.svg?style=flat-square [badge_quality]: https://img.shields.io/scrutinizer/g/ARCANEDEV/Support.svg?style=flat-square [badge_insight]: https://img.shields.io/sensiolabs/i/de0353dd-df17-4656-b9c0-1eea95aa30a2.svg?style=flat-square [badge_issues]: https://img.shields.io/github/issues/ARCANEDEV/Support.svg?style=flat-square [badge_package]: https://img.shields.io/badge/package-arcanedev/support-blue.svg?style=flat-square [badge_release]: https://img.shields.io/packagist/v/arcanedev/support.svg?style=flat-square [badge_downloads]: https://img.shields.io/packagist/dt/arcanedev/support.svg?style=flat-square [link-author]: https://github.com/arcanedev-maroc [link-github-repo]: https://github.com/ARCANEDEV/Support [link-github-status]: https://github.com/ARCANEDEV/Support/actions [link-github-issues]: https://github.com/ARCANEDEV/Support/issues [link-contributors]: https://github.com/ARCANEDEV/Support/graphs/contributors [link-packagist]: https://packagist.org/packages/arcanedev/support [link-scrutinizer]: https://scrutinizer-ci.com/g/ARCANEDEV/Support/?branch=master [link-insight]: https://insight.sensiolabs.com/projects/de0353dd-df17-4656-b9c0-1eea95aa30a2 support/src/Console/Command.php 0000644 00000002355 15002151620 0012535 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Console; use Illuminate\Console\Command as IlluminateCommand; use Symfony\Component\Console\Helper\TableSeparator; /** * Class Command * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class Command extends IlluminateCommand { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Execute the console command. */ abstract public function handle(); /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Create table separator * * @return \Symfony\Component\Console\Helper\TableSeparator */ protected function tableSeparator() { return new TableSeparator; } /** * Display frame the text info. * * @param string $text */ protected function frame(string $text) { $line = '+'.str_repeat('-', strlen($text) + 4).'+'; $this->info($line); $this->info("| $text |"); $this->info($line); } } support/src/Exceptions/PackageException.php 0000644 00000000552 15002151620 0015105 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Exceptions; use Exception; /** * Class PackageException * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class PackageException extends Exception { public static function unspecifiedName(): self { return new static('You must specify the vendor/package name.'); } } support/src/Middleware/VerifyJsonRequest.php 0000644 00000005410 15002151620 0015274 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Middleware; use Closure; use Illuminate\Http\{JsonResponse, Request, Response}; /** * Class VerifyJsonRequest * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class VerifyJsonRequest { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Supported request method verbs. * * @var array */ protected $methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param string|array|null $methods * * @return mixed */ public function handle(Request $request, Closure $next, $methods = null) { if ($this->isJsonRequestValid($request, $methods)) { return $next($request); } return $this->jsonErrorResponse(); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Validate json Request. * * @param \Illuminate\Http\Request $request * @param string|array|null $methods * * @return bool */ protected function isJsonRequestValid(Request $request, $methods) { $methods = $this->getMethods($methods); if ( ! in_array($request->method(), $methods)) { return false; } return $request->isJson(); } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get the error as json response. * * @return \Illuminate\Http\JsonResponse */ protected function jsonErrorResponse() { $data = [ 'status' => 'error', 'code' => $statusCode = Response::HTTP_BAD_REQUEST, 'message' => 'Request must be JSON', ]; return new JsonResponse($data, $statusCode); } /** * Get request methods. * * @param string|array|null $methods * * @return array */ protected function getMethods($methods): array { $methods = $methods ?? $this->methods; if (is_string($methods)) { $methods = (array) $methods; } return is_array($methods) ? array_map('strtoupper', $methods) : []; } } support/src/Routing/Concerns/RegistersRouteClasses.php 0000644 00000002014 15002151620 0017252 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Routing\Concerns; /** * Trait RegistersRouteClasses * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait RegistersRouteClasses { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Map route classes. * * @param iterable $routes */ protected static function mapRouteClasses(iterable $routes): void { foreach ($routes as $route) { if (method_exists($route, 'map')) { app()->call("{$route}@map"); } } } /** * Bind route classes. * * @param iterable $routes */ protected static function bindRouteClasses(iterable $routes): void { foreach ($routes as $route) { if (method_exists($route, 'bindings')) { app()->call("{$route}@bindings"); } } } } support/src/Routing/RouteRegistrar.php 0000644 00000003452 15002151620 0014164 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Routing; use Arcanedev\Support\Routing\Concerns\RegistersRouteClasses; use Illuminate\Contracts\Routing\Registrar; use Illuminate\Routing\Router; use Illuminate\Support\Traits\ForwardsCalls; /** * Class RouteRegistrar * * @author ARCANEDEV <arcanedev.maroc@gmail.com> * * @method \Illuminate\Routing\RouteRegistrar bind(string $key, \Closure $binder) * @method void map() * @method void bindings() * * @mixin \Illuminate\Routing\RouteRegistrar */ abstract class RouteRegistrar { /* ----------------------------------------------------------------- | Traits | ----------------------------------------------------------------- */ use RegistersRouteClasses, ForwardsCalls; /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Pass dynamic methods onto the router instance. * * @param string $method * @param array $parameters * * @return mixed */ public function __call($method, $parameters) { return $this->forwardCallToRouter( app(Router::class), $method, $parameters ); } /** * Pass dynamic methods onto the router instance. * * @param \Illuminate\Contracts\Routing\Registrar $router * @param string $method * @param array $parameters * * @return mixed */ protected function forwardCallToRouter(Registrar $router, $method, $parameters) { return $this->forwardCallTo($router, $method, $parameters); } } support/src/Providers/ViewComposerServiceProvider.php 0000644 00000003511 15002151620 0017203 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; use Illuminate\Contracts\View\Factory as ViewFactory; /** * Class ViewComposerServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class ViewComposerServiceProvider extends ServiceProvider { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Register the composer classes. * * @var array */ protected $composerClasses = [ // 'view-name' => 'class' ]; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Boot the view composer service provider. */ public function boot() { $this->registerComposerClasses(); } /** * Register the view composer classes. */ protected function registerComposerClasses() { foreach ($this->composerClasses as $view => $class) { $this->composer($view, $class); } } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get the view factory instance. * * @return \Illuminate\Contracts\View\Factory */ protected function view() { return $this->app->make(ViewFactory::class); } /** * Register a view composer event. * * @param array|string $views * @param \Closure|string $callback * * @return array */ public function composer($views, $callback) { return $this->view()->composer($views, $callback); } } support/src/Providers/EventServiceProvider.php 0000644 00000003224 15002151620 0015643 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; use Illuminate\Support\Facades\Event; /** * Class EventServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class EventServiceProvider extends ServiceProvider { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The event handler mappings for the application. * * @var array */ protected $listen = []; /** * The subscriber classes to register. * * @var array */ protected $subscribe = []; /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the events and handlers. * * @return array */ public function listens() { return $this->listen; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Register the application's event listeners. */ public function boot() { foreach ($this->listens() as $event => $listeners) { foreach ($listeners as $listener) { Event::listen($event, $listener); } } foreach ($this->subscribe as $subscriber) { Event::subscribe($subscriber); } } /** * {@inheritdoc} */ public function register() { // } } support/src/Providers/PackageServiceProvider.php 0000644 00000010667 15002151620 0016126 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; use Arcanedev\Support\Exceptions\PackageException; use Arcanedev\Support\Providers\Concerns\{ HasAssets, HasConfig, HasFactories, HasMigrations, HasTranslations, HasViews }; use Illuminate\Contracts\Foundation\Application; use Illuminate\Support\Str; use ReflectionClass; /** * Class PackageServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class PackageServiceProvider extends ServiceProvider { /* ----------------------------------------------------------------- | Traits | ----------------------------------------------------------------- */ use HasAssets, HasConfig, HasFactories, HasMigrations, HasTranslations, HasViews; /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Vendor name. * * @var string */ protected $vendor = 'arcanedev'; /** * Package name. * * @var string|null */ protected $package; /** * Package base path. * * @var string */ protected $basePath; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create a new service provider instance. * * @param \Illuminate\Contracts\Foundation\Application $app */ public function __construct(Application $app) { parent::__construct($app); $this->basePath = $this->resolveBasePath(); } /** * Resolve the base path of the package. * * @return string */ protected function resolveBasePath() { return dirname( (new ReflectionClass($this))->getFileName(), 2 ); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the base path of the package. * * @return string */ public function getBasePath() { return $this->basePath; } /** * Get the vendor name. * * @return string */ protected function getVendorName(): string { return $this->vendor; } /** * Get the package name. * * @return string|null */ protected function getPackageName(): ?string { return $this->package; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Register the service provider. */ public function register() { parent::register(); $this->checkPackageName(); } /* ----------------------------------------------------------------- | Package Methods | ----------------------------------------------------------------- */ /** * Publish all the package files. */ protected function publishAll(): void { $this->publishAssets(); $this->publishConfig(); $this->publishFactories(); $this->publishMigrations(); $this->publishTranslations(); $this->publishViews(); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Check package name. * * @throws \Arcanedev\Support\Exceptions\PackageException */ protected function checkPackageName(): void { if (empty($this->getVendorName()) || empty($this->getPackageName())) { throw PackageException::unspecifiedName(); } } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Get the published tags. * * @param string $tag * * @return array */ protected function getPublishedTags(string $tag): array { $package = $this->getPackageName(); return array_map(function ($name) { return Str::slug($name); }, [$this->getVendorName(), $package, $tag, $package.'-'.$tag]); } } support/src/Providers/RouteServiceProvider.php 0000644 00000001132 15002151620 0015654 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; use Arcanedev\Support\Routing\Concerns\RegistersRouteClasses; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as IlluminateServiceProvider; /** * Class RouteServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class RouteServiceProvider extends IlluminateServiceProvider { /* ----------------------------------------------------------------- | Traits | ----------------------------------------------------------------- */ use RegistersRouteClasses; } support/src/Providers/AuthorizationServiceProvider.php 0000644 00000001476 15002151620 0017431 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; use Illuminate\Foundation\Support\Providers\AuthServiceProvider; use Illuminate\Support\Facades\Gate; /** * Class AuthorizationServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class AuthorizationServiceProvider extends AuthServiceProvider { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Define policies. * * @param string $class * @param array $policies */ protected function defineMany($class, array $policies) { foreach ($policies as $ability => $method) { Gate::define($ability, "$class@$method"); } } } support/src/Providers/CommandServiceProvider.php 0000644 00000002125 15002151620 0016137 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; /** * Class CommandServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class CommandServiceProvider extends ServiceProvider { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The commands to be registered. * * @var array */ protected $commands = []; /** * Indicates if loading of the provider is deferred. * * @var bool */ protected $defer = true; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Boot the service provider. */ public function boot() { $this->commands($this->commands); } /** * Get the provided commands. * * @return array */ public function provides() { return $this->commands; } } support/src/Providers/Concerns/InteractsWithApplication.php 0000644 00000004706 15002151620 0020262 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; /** * Trait InteractsWithApplication * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait InteractsWithApplication { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Register multiple service providers. * * @param array $providers */ protected function registerProviders(array $providers) { foreach ($providers as $provider) { $this->registerProvider($provider); } } /** * Register a service provider. * * @param \Illuminate\Support\ServiceProvider|string $provider * @param bool $force * * @return \Illuminate\Support\ServiceProvider */ protected function registerProvider($provider, $force = false) { return $this->app->register($provider, $force); } /** * Register a console service provider. * * @param \Illuminate\Support\ServiceProvider|string $provider * @param bool $force * * @return \Illuminate\Support\ServiceProvider|null */ protected function registerConsoleServiceProvider($provider, $force = false) { if ($this->app->runningInConsole()) { return $this->registerProvider($provider, $force); } return null; } /** * Register the package's custom Artisan commands when running in console. * * @param array $commands */ protected function registerCommands(array $commands) { if ($this->app->runningInConsole()) { $this->commands($commands); } } /** * Register a binding with the container. * * @param string $abstract * @param \Closure|string|null $concrete * @param bool $shared */ protected function bind($abstract, $concrete = null, $shared = false) { $this->app->bind($abstract, $concrete, $shared); } /** * Register a shared binding in the container. * * @param string|array $abstract * @param \Closure|string|null $concrete */ protected function singleton($abstract, $concrete = null) { $this->app->singleton($abstract, $concrete); } } support/src/Providers/Concerns/HasFactories.php 0000644 00000002105 15002151620 0015650 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; /** * Trait HasFactories * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait HasFactories { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get the migrations path. * * @return string */ protected function getFactoriesPath(): string { return $this->getBasePath().DIRECTORY_SEPARATOR.'database'.DIRECTORY_SEPARATOR.'factories'; } /** * Publish the factories. * * @param string|null $path */ protected function publishFactories(?string $path = null): void { $this->publishes([ $this->getFactoriesPath() => $path ?: database_path('factories'), ], $this->getPublishedTags('factories')); } /** * Load the factories. */ protected function loadFactories(): void { $this->loadFactoriesFrom($this->getFactoriesPath()); } } support/src/Providers/Concerns/HasTranslations.php 0000644 00000003242 15002151620 0016415 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; /** * Trait HasTranslations * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait HasTranslations { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get the translations' folder name. */ protected function getTranslationsFolderName(): string { return 'translations'; } /** * Get the translations' path. */ protected function getTranslationsPath(): string { return $this->getBasePath().DIRECTORY_SEPARATOR.$this->getTranslationsFolderName(); } /** * Get the destination views path. */ protected function getTranslationsDestinationPath(): string { return $this->app->langPath( 'vendor'.DIRECTORY_SEPARATOR.$this->getPackageName() ); } /** * Publish the translations. */ protected function publishTranslations(?string $path = null): void { $this->publishes([ $this->getTranslationsPath() => $path ?: $this->getTranslationsDestinationPath(), ], $this->getPublishedTags('translations')); } /** * Load the translations files. */ protected function loadTranslations(): void { $packagePath = $this->getTranslationsPath(); $vendorPath = $this->getTranslationsDestinationPath(); $this->loadTranslationsFrom($packagePath, $this->getPackageName()); $this->loadJsonTranslationsFrom(file_exists($vendorPath) ? $vendorPath : $packagePath); } } support/src/Providers/Concerns/HasConfig.php 0000644 00000007255 15002151620 0015151 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; use Illuminate\Support\Str; /** * Trait HasConfig * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait HasConfig { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Merge multiple config files into one instance (package name as root key) * * @var bool */ protected $multiConfigs = false; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get config folder. * * @return string */ protected function getConfigFolder(): string { return realpath($this->getBasePath().DIRECTORY_SEPARATOR.'config'); } /** * Get config key. * * @param bool $withVendor * @param string $separator * * @return string */ protected function getConfigKey(bool $withVendor = false, string $separator = '.'): string { $package = Str::slug($this->getPackageName()); return $withVendor ? Str::slug($this->getVendorName()).$separator.$package : $package; } /** * Get config file path. * * @return string */ protected function getConfigFile(): string { return $this->getConfigFolder().DIRECTORY_SEPARATOR."{$this->getPackageName()}.php"; } /** * Get the config files (paths). * * @return array|false */ protected function configFilesPaths() { return glob($this->getConfigFolder().DIRECTORY_SEPARATOR.'*.php'); } /** * Register configs. * * @param string $separator */ protected function registerConfig(string $separator = '.'): void { $this->multiConfigs ? $this->registerMultipleConfigs($separator) : $this->registerSingleConfig(); } /** * Register a single config file. */ protected function registerSingleConfig(): void { $this->mergeConfigFrom($this->getConfigFile(), $this->getConfigKey()); } /** * Register all package configs. * * @param string $separator */ protected function registerMultipleConfigs(string $separator = '.'): void { foreach ($this->configFilesPaths() as $path) { $key = $this->getConfigKey(true, $separator).$separator.basename($path, '.php'); $this->mergeConfigFrom($path, $key); } } /** * Publish the config file. * * @param string|null $path */ protected function publishConfig(?string $path = null): void { $this->multiConfigs ? $this->publishMultipleConfigs() : $this->publishSingleConfig($path); } /** * Publish a single config file. * * @param string|null $path */ protected function publishSingleConfig(?string $path = null): void { $this->publishes([ $this->getConfigFile() => $path ?: config_path("{$this->getPackageName()}.php"), ], $this->getPublishedTags('config')); } /** * Publish multiple config files. */ protected function publishMultipleConfigs(): void { $paths = []; $package = $this->getConfigKey(true, DIRECTORY_SEPARATOR); foreach ($this->configFilesPaths() as $file) { $paths[$file] = config_path($package.DIRECTORY_SEPARATOR.basename($file)); } $this->publishes($paths, $this->getPublishedTags('config')); } } support/src/Providers/Concerns/HasViews.php 0000644 00000002464 15002151620 0015036 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; /** * Trait HasViews * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait HasViews { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get the base views path. * * @return string */ protected function getViewsPath(): string { return $this->getBasePath().DIRECTORY_SEPARATOR.'views'; } /** * Get the destination views path. * * @return string */ protected function getViewsDestinationPath(): string { return $this->app['config']['view.paths'][0].DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR.$this->getPackageName(); } /** * Publish the views. * * @param string|null $path */ protected function publishViews(?string $path = null): void { $this->publishes([ $this->getViewsPath() => $path ?: $this->getViewsDestinationPath(), ], $this->getPublishedTags('views')); } /** * Load the views files. */ protected function loadViews(): void { $this->loadViewsFrom($this->getViewsPath(), $this->getPackageName()); } } support/src/Providers/Concerns/HasMigrations.php 0000644 00000002134 15002151620 0016047 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; /** * Trait HasMigrations * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait HasMigrations { /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Get the migrations path. * * @return string */ protected function getMigrationsPath(): string { return $this->getBasePath().DIRECTORY_SEPARATOR.'database'.DIRECTORY_SEPARATOR.'migrations'; } /** * Publish the migration files. * * @param string|null $path */ protected function publishMigrations(?string $path = null): void { $this->publishes([ $this->getMigrationsPath() => $path ?: database_path('migrations') ], $this->getPublishedTags('migrations')); } /** * Load the migrations files. */ protected function loadMigrations(): void { $this->loadMigrationsFrom($this->getMigrationsPath()); } } support/src/Providers/Concerns/HasAssets.php 0000644 00000002327 15002151620 0015201 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers\Concerns; /** * Trait HasAssets * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ trait HasAssets { /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the assets path. * * @return string */ protected function getAssetsFolder(): string { return realpath($this->getBasePath().DIRECTORY_SEPARATOR.'assets'); } /** * Get the assets destination path. * * @return string */ protected function assetsDestinationPath(): string { return base_path('assets'.DIRECTORY_SEPARATOR.$this->getPackageName()); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Publish the assets. */ protected function publishAssets(): void { $this->publishes([ $this->getAssetsFolder() => $this->assetsDestinationPath(), ], $this->getPublishedTags('assets')); } } support/src/Providers/ServiceProvider.php 0000644 00000001076 15002151620 0014644 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Providers; use Arcanedev\Support\Providers\Concerns\InteractsWithApplication; use Illuminate\Support\ServiceProvider as IlluminateServiceProvider; /** * Class ServiceProvider * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class ServiceProvider extends IlluminateServiceProvider { /* ----------------------------------------------------------------- | Traits | ----------------------------------------------------------------- */ use InteractsWithApplication; } support/src/Validation/Rule.php 0000644 00000003101 15002151620 0012544 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Validation; use Illuminate\Contracts\Validation\Rule as RuleContract; /** * Class Rule * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class Rule implements RuleContract { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The message that should be used when validation fails. * * @var string|array */ protected $message; /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Set the message that should be used when the rule fails. * * @param string|array $message * * @return $this */ public function withMessage($message) { $this->message = $message; return $this; } /** * Get the validation error message. * * @return string|array */ public function message() { return $this->message; } /* ----------------------------------------------------------------- | Other Methods | ----------------------------------------------------------------- */ /** * Fail if the validation rule. * * @param string|array $message * * @return bool */ protected function fail($message): bool { $this->withMessage($message); return false; } } support/src/Database/Migration.php 0000644 00000007502 15002151620 0013211 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Database; use Closure; use Illuminate\Database\Migrations\Migration as IlluminateMigration; use Illuminate\Database\Schema\Builder; /** * Class Migration * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class Migration extends IlluminateMigration { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The table name. * * @var string|null */ protected $table; /** * The table prefix. * * @var string|null */ protected $prefix; /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get a schema builder instance for the connection. * * @return \Illuminate\Database\Schema\Builder */ protected function getSchemaBuilder(): Builder { /** @var \Illuminate\Database\DatabaseManager $db */ $db = app()->make('db'); return $db->connection($this->hasConnection() ? $this->getConnection() : null) ->getSchemaBuilder(); } /** * Set the migration connection name. * * @param string $connection * * @return $this */ public function setConnection($connection) { $this->connection = $connection; return $this; } /** * Get the prefixed table name. * * @return string */ public function getTableName() { return $this->hasPrefix() ? $this->prefix.$this->table : $this->table; } /** * Set the table name. * * @param string $table * * @return $this */ public function setTable($table) { $this->table = $table; return $this; } /** * Set the prefix name. * * @param string $prefix * * @return $this */ public function setPrefix($prefix) { $this->prefix = $prefix; return $this; } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Migrate to database. */ abstract public function up(): void; /** * Rollback the migration. */ public function down(): void { $this->getSchemaBuilder()->dropIfExists($this->getTableName()); } /** * Create Table Schema. * * @param \Closure $blueprint */ protected function createSchema(Closure $blueprint): void { $this->getSchemaBuilder()->create($this->getTableName(), $blueprint); } /** * Modify a table on the schema. * * @param \Closure $callback */ protected function table(Closure $callback): void { $this->getSchemaBuilder()->table($this->getTableName(), $callback); } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Check if connection exists. * * @return bool */ protected function hasConnection(): bool { return $this->isNotEmpty($this->getConnection()); } /** * Check if table has prefix. * * @return bool */ protected function hasPrefix(): bool { return $this->isNotEmpty($this->prefix); } /** * Check if the value is not empty. * * @param string|null $value * * @return bool */ private function isNotEmpty($value): bool { return ! (is_null($value) || empty($value)); } } support/src/Database/PrefixedModel.php 0000644 00000003252 15002151620 0014005 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Database; use Illuminate\Database\Eloquent\Model; /** * Class PrefixedModel * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class PrefixedModel extends Model { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The table prefix. * * @var string|null */ protected $prefix; /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get the table associated with the model. * * @return string */ public function getTable() { return $this->getPrefix().parent::getTable(); } /** * Get the prefix table associated with the model. * * @return string */ public function getPrefix(): string { return $this->isPrefixed() ? $this->prefix : ''; } /** * Set the prefix table associated with the model. * * @param string|null $prefix * * @return $this */ public function setPrefix(?string $prefix) { $this->prefix = $prefix; return $this; } /* ----------------------------------------------------------------- | Check Methods | ----------------------------------------------------------------- */ /** * Check if table is prefixed. * * @return bool */ public function isPrefixed(): bool { return ! is_null($this->prefix); } } support/src/Database/Seeder.php 0000644 00000001736 15002151620 0012472 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support\Database; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Seeder as IlluminateSeeder; /** * Class Seeder * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ abstract class Seeder extends IlluminateSeeder { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * Seeder collection. * * @var array */ protected $seeds = []; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Run the database seeds. */ public function run(): void { Eloquent::unguard(); foreach ($this->seeds as $seed) { $this->call($seed); } Eloquent::reguard(); } } support/src/Stub.php 0000644 00000011373 15002151620 0010472 0 ustar 00 <?php declare(strict_types=1); namespace Arcanedev\Support; /** * Class Stub * * @author ARCANEDEV <arcanedev.maroc@gmail.com> */ class Stub { /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- */ /** * The stub path. * * @var string */ protected $path; /** * The base path of stub file. * * @var string|null */ protected static $basePath = null; /** * The replacements array. * * @var array */ protected $replaces = []; /* ----------------------------------------------------------------- | Constructor | ----------------------------------------------------------------- */ /** * Create a new instance. * * @param string $path * @param array $replaces */ public function __construct($path, array $replaces = []) { $this->setPath($path); $this->setReplaces($replaces); } /* ----------------------------------------------------------------- | Getters & Setters | ----------------------------------------------------------------- */ /** * Get stub path. * * @return string */ public function getPath(): string { $path = $this->path; if ( ! empty(static::$basePath)) { $path = static::$basePath.DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR); } return $path; } /** * Set stub path. * * @param string $path * * @return $this */ public function setPath(string $path): self { $this->path = $path; return $this; } /** * Get base path. * * @return string|null */ public static function getBasePath(): ?string { return static::$basePath; } /** * Set base path. * * @param string $path */ public static function setBasePath(string $path) { static::$basePath = $path; } /** * Get replacements. * * @return array */ public function getReplaces(): array { return $this->replaces; } /** * Set replacements array. * * @param array $replaces * * @return $this */ public function setReplaces(array $replaces = []): self { $this->replaces = $replaces; return $this; } /** * Set replacements array. * * @param array $replaces * * @return $this */ public function replaces(array $replaces = []): self { return $this->setReplaces($replaces); } /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ /** * Create new self instance. * * @param string $path * @param array $replaces * * @return $this */ public static function create(string $path, array $replaces = []): self { return new static($path, $replaces); } /** * Create new self instance from full path. * * @param string $path * @param array $replaces * * @return $this */ public static function createFromPath(string $path, array $replaces = []): self { return tap(new static($path, $replaces), function (self $stub) { $stub->setBasePath(''); }); } /** * Get stub contents. * * @return string */ public function render(): string { return $this->getContents(); } /** * Save stub to base path. * * @param string $filename * * @return bool */ public function save(string $filename): bool { return $this->saveTo(self::getBasePath(), $filename); } /** * Save stub to specific path. * * @param string $path * @param string $filename * * @return bool */ public function saveTo(string $path, string $filename): bool { return file_put_contents($path.DIRECTORY_SEPARATOR.$filename, $this->render()) !== false; } /** * Get stub contents. * * @return string|mixed */ public function getContents() { $contents = file_get_contents($this->getPath()); foreach ($this->getReplaces() as $search => $replace) { $contents = str_replace('$'.strtoupper($search).'$', $replace, $contents); } return $contents; } /** * Handle magic method __toString. * * @return string */ public function __toString(): string { return $this->render(); } } support/LICENSE.md 0000644 00000002113 15002151620 0007651 0 ustar 00 The MIT License (MIT) Copyright (c) ARCANEDEV <arcanedev.maroc@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| ver. 1.4 |
Github
|
.
| PHP 8.2.28 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings