Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Satini_pvduc
/
daito-utils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Authored by
RESAZIP-PC\resaz
2026-02-23 23:26:40 +0700
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Commit
9fe3ba35981b840abdc55f1d3798bc27c7f3441b
9fe3ba35
1 parent
3aef053c
add daitoexceptionnotifier
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
586 additions
and
1 deletions
README.md
composer.json
src/DaitoExceptionNotifier.php
src/DaitoExceptionNotifier/DaitoExceptionNotifierManager.php
src/DaitoExceptionNotifier/Providers/DaitoExceptionNotifierProvider.php
src/DaitoExceptionNotifier/config/daito-exception-notifier.php
README.md
View file @
9fe3ba3
...
...
@@ -257,6 +257,93 @@ DAITO_GOOGLE_CHAT_VERIFY_SSL=false
Use this only for temporary debugging on local environment. Never disable SSL verification on production.
## DaitoExceptionNotifier (separate reusable module)
### 1) Publish config
```
bash
php artisan vendor:publish --tag
=
daito-exception-notifier-config
```
This creates
`config/daito-exception-notifier.php`
.
### 2) Minimal `.env` setup
```
dotenv
DAITO_EXCEPTION_NOTIFIER_ENABLED=true
DAITO_EXCEPTION_NOTIFIER_SEND_MODE=queue
DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_ENABLED=true
DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_TTL_SECONDS=30
DAITO_EXCEPTION_NOTIFIER_TRACE_MODE=smart
DAITO_EXCEPTION_NOTIFIER_TRACE_MAX_LINES=8
DAITO_EXCEPTION_NOTIFIER_TRACE_SKIP_VENDOR=true
DAITO_EXCEPTION_NOTIFIER_TRACE_INCLUDE_FIRST_APP_FRAME=true
```
### 3) Auto notify on exception (HTTP + CLI)
Use Laravel exception handler to automatically send exception cardV2:
```
php
<?php
namespace
App\Exceptions
;
use
Daito\Lib\DaitoExceptionNotifier
;
use
Illuminate\Foundation\Exceptions\Handler
as
ExceptionHandler
;
use
Throwable
;
class
Handler
extends
ExceptionHandler
{
public
function
register
()
{
$this
->
reportable
(
function
(
Throwable
$throwable
)
{
DaitoExceptionNotifier
::
notify
(
$throwable
);
});
}
}
```
`DaitoExceptionNotifier::notify()`
supports both route/controller errors and CLI command errors because Laravel routes both through the same exception handler.
If you want explicit mode:
```
php
DaitoExceptionNotifier::queue($throwable); // queue
DaitoExceptionNotifier::send($throwable); // sync immediate
```
Exception cardV2 includes:
-
`time`
-
`action`
-
`file`
-
`line`
-
`message`
-
compact
`trace`
(top useful frames only, configurable)
-
`first_app_frame`
(when available)
Trace filter strategy (
`DAITO_EXCEPTION_NOTIFIER_TRACE_MODE`
):
-
`smart`
(recommended): prefer app frames, then non-vendor frames, then fallback
-
`app_only`
: only frames that belong to
`app/`
or class prefix
`App\`
- `
no_vendor
`: remove `
vendor
` frames
- `
class_prefix_only
`: only frames by configured class prefixes (`
trace_class_prefixes
`)
### 4) Built-in loop guard (recommended default)
To avoid recursive notify loops when Google Chat send itself throws exceptions, this module has a built-in circuit-breaker:
- re-entrant guard in the same process/request
- short TTL dedupe by exception fingerprint (file+line+message+action)
- optional cache-based dedupe across workers/processes
Main config keys:
- `
loop_guard_enabled
`
- `
loop_guard_ttl_seconds
`
- `
loop_guard_use_cache
`
- `
loop_guard_cache_prefix
`
- `
loop_guard_skip_if_notifier_in_trace
`
## QueryLog (Laravel shared package)
> **Provider registration note**
...
...
composer.json
View file @
9fe3ba3
...
...
@@ -21,7 +21,8 @@
"laravel"
:
{
"providers"
:
[
"Daito
\\
Lib
\\
DaitoQueryLog
\\
Providers
\\
DaitoQueryLogProvider"
,
"Daito
\\
Lib
\\
DaitoGoogleChat
\\
Providers
\\
DaitoGoogleChatProvider"
"Daito
\\
Lib
\\
DaitoGoogleChat
\\
Providers
\\
DaitoGoogleChatProvider"
,
"Daito
\\
Lib
\\
DaitoExceptionNotifier
\\
Providers
\\
DaitoExceptionNotifierProvider"
]
}
}
...
...
src/DaitoExceptionNotifier.php
0 → 100644
View file @
9fe3ba3
<?php
namespace
Daito\Lib
;
use
Daito\Lib\DaitoExceptionNotifier\DaitoExceptionNotifierManager
;
use
RuntimeException
;
use
Throwable
;
class
DaitoExceptionNotifier
{
public
static
function
send
(
Throwable
$throwable
,
array
$arrContext
=
array
(),
$webhookUrl
=
null
)
:
array
{
return
self
::
manager
()
->
send
(
$throwable
,
$arrContext
,
$webhookUrl
);
}
public
static
function
queue
(
Throwable
$throwable
,
array
$arrContext
=
array
(),
$webhookUrl
=
null
)
:
void
{
self
::
manager
()
->
queue
(
$throwable
,
$arrContext
,
$webhookUrl
);
}
public
static
function
notify
(
Throwable
$throwable
,
array
$arrContext
=
array
(),
$webhookUrl
=
null
)
{
return
self
::
manager
()
->
notify
(
$throwable
,
$arrContext
,
$webhookUrl
);
}
private
static
function
manager
()
:
DaitoExceptionNotifierManager
{
if
(
!
function_exists
(
'app'
))
{
throw
new
RuntimeException
(
'Laravel app container is required for DaitoExceptionNotifier.'
);
}
$manager
=
app
(
DaitoExceptionNotifierManager
::
class
);
if
(
!
$manager
instanceof
DaitoExceptionNotifierManager
)
{
throw
new
RuntimeException
(
'Can not resolve DaitoExceptionNotifierManager from container.'
);
}
return
$manager
;
}
}
src/DaitoExceptionNotifier/DaitoExceptionNotifierManager.php
0 → 100644
View file @
9fe3ba3
<?php
namespace
Daito\Lib\DaitoExceptionNotifier
;
use
Daito\Lib\DaitoGoogleChat\DaitoGoogleChatManager
;
use
Throwable
;
class
DaitoExceptionNotifierManager
{
/**
* Guard re-entrant notify in same process.
*
* @var bool
*/
private
static
$isNotifying
=
false
;
/**
* Lightweight per-process cooldown by fingerprint.
*
* @var array<string, float>
*/
private
static
$arrFingerprintCooldowns
=
array
();
/**
* @var \Daito\Lib\DaitoGoogleChat\DaitoGoogleChatManager
*/
private
$daitoGoogleChatManager
;
public
function
__construct
(
DaitoGoogleChatManager
$daitoGoogleChatManager
)
{
$this
->
daitoGoogleChatManager
=
$daitoGoogleChatManager
;
}
public
function
send
(
Throwable
$throwable
,
array
$arrContext
=
array
(),
$webhookUrl
=
null
)
:
array
{
if
(
!
(
bool
)
config
(
'daito-exception-notifier.enabled'
,
true
))
{
return
array
(
'success'
=>
0
,
'status'
=>
'disabled'
,
);
}
return
$this
->
daitoGoogleChatManager
->
sendCardV2
(
$this
->
buildCardV2
(
$throwable
,
$arrContext
),
$webhookUrl
);
}
public
function
queue
(
Throwable
$throwable
,
array
$arrContext
=
array
(),
$webhookUrl
=
null
)
:
void
{
if
(
!
(
bool
)
config
(
'daito-exception-notifier.enabled'
,
true
))
{
return
;
}
$this
->
daitoGoogleChatManager
->
queueCardV2
(
$this
->
buildCardV2
(
$throwable
,
$arrContext
),
$webhookUrl
);
}
public
function
notify
(
Throwable
$throwable
,
array
$arrContext
=
array
(),
$webhookUrl
=
null
)
{
if
(
!
(
bool
)
config
(
'daito-exception-notifier.enabled'
,
true
))
{
return
array
(
'success'
=>
0
,
'status'
=>
'disabled'
,
);
}
if
(
$this
->
shouldBlockByLoopGuard
(
$throwable
,
$arrContext
))
{
return
array
(
'success'
=>
0
,
'status'
=>
'blocked_loop_guard'
,
);
}
$mode
=
strtolower
((
string
)
config
(
'daito-exception-notifier.send_mode'
,
'queue'
));
self
::
$isNotifying
=
true
;
try
{
if
(
$mode
===
'sync'
||
$mode
===
'immediate'
)
{
return
$this
->
send
(
$throwable
,
$arrContext
,
$webhookUrl
);
}
$this
->
queue
(
$throwable
,
$arrContext
,
$webhookUrl
);
return
array
(
'success'
=>
1
,
'status'
=>
'queued'
,
);
}
finally
{
self
::
$isNotifying
=
false
;
}
}
private
function
buildCardV2
(
Throwable
$throwable
,
array
$arrContext
=
array
())
:
array
{
$action
=
isset
(
$arrContext
[
'action'
])
?
(
string
)
$arrContext
[
'action'
]
:
$this
->
resolveCurrentAction
();
$arrTraceData
=
$this
->
extractTraceData
(
$throwable
);
$arrSummaryWidgets
=
array
(
$this
->
makeDecoratedTextWidget
(
'time'
,
date
(
'Y-m-d H:i:s'
)),
$this
->
makeDecoratedTextWidget
(
'action'
,
$action
),
$this
->
makeDecoratedTextWidget
(
'file'
,
(
string
)
$throwable
->
getFile
()),
$this
->
makeDecoratedTextWidget
(
'line'
,
(
string
)
$throwable
->
getLine
()),
$this
->
makeDecoratedTextWidget
(
'message'
,
$this
->
limitText
((
string
)
$throwable
->
getMessage
(),
(
int
)
config
(
'daito-exception-notifier.message_max_length'
,
1000
))
),
);
if
((
bool
)
config
(
'daito-exception-notifier.trace_include_first_app_frame'
,
true
)
&&
$arrTraceData
[
'first_app_frame'
]
!==
''
)
{
$arrSummaryWidgets
[]
=
$this
->
makeDecoratedTextWidget
(
'first_app_frame'
,
$arrTraceData
[
'first_app_frame'
]);
}
return
array
(
'cardId'
=>
'daito-exception-alert'
,
'card'
=>
array
(
'header'
=>
array
(
'title'
=>
(
string
)
config
(
'daito-exception-notifier.card_title'
,
'Exception Alert'
),
'subtitle'
=>
$action
,
),
'sections'
=>
array
(
array
(
'header'
=>
'Summary'
,
'widgets'
=>
$arrSummaryWidgets
,
),
array
(
'header'
=>
'Trace'
,
'widgets'
=>
array
(
array
(
'textParagraph'
=>
array
(
'text'
=>
$this
->
escapeForGoogleChat
(
$arrTraceData
[
'trace'
]),
),
),
),
),
),
),
);
}
private
function
extractTraceData
(
Throwable
$throwable
)
:
array
{
$maxLines
=
max
(
1
,
(
int
)
config
(
'daito-exception-notifier.trace_max_lines'
,
8
));
$maxLength
=
(
int
)
config
(
'daito-exception-notifier.trace_max_length'
,
2500
);
$traceMode
=
strtolower
((
string
)
config
(
'daito-exception-notifier.trace_mode'
,
'smart'
));
$skipVendor
=
(
bool
)
config
(
'daito-exception-notifier.trace_skip_vendor'
,
true
);
$arrTrace
=
(
array
)
$throwable
->
getTrace
();
$rootDir
=
function_exists
(
'base_path'
)
?
str_replace
(
'\\'
,
'/'
,
base_path
())
:
''
;
$appDir
=
function_exists
(
'base_path'
)
?
str_replace
(
'\\'
,
'/'
,
base_path
(
'app'
))
:
''
;
$arrClassPrefixes
=
(
array
)
config
(
'daito-exception-notifier.trace_class_prefixes'
,
array
(
'App\\'
));
$arrMappedFrames
=
array
();
$arrAppFrames
=
array
();
$arrNonVendorFrames
=
array
();
foreach
(
$arrTrace
as
$index
=>
$arrFrame
)
{
$arrFrameInfo
=
$this
->
mapTraceFrame
(
$arrFrame
,
$index
);
$arrMappedFrames
[]
=
$arrFrameInfo
;
if
(
$this
->
isAppFrame
(
$arrFrameInfo
,
$appDir
,
$arrClassPrefixes
))
{
$arrAppFrames
[]
=
$arrFrameInfo
;
}
if
(
!
$this
->
isVendorPath
(
$arrFrameInfo
[
'file'
],
$rootDir
))
{
$arrNonVendorFrames
[]
=
$arrFrameInfo
;
}
}
$arrSelectedFrames
=
$this
->
selectTraceFramesByMode
(
$traceMode
,
$arrMappedFrames
,
$arrAppFrames
,
$arrNonVendorFrames
,
$skipVendor
,
$maxLines
);
if
(
$arrSelectedFrames
===
array
())
{
$arrSelectedFrames
=
array_slice
(
$arrMappedFrames
,
0
,
$maxLines
);
}
$arrTraceLines
=
array
();
foreach
(
$arrSelectedFrames
as
$arrFrameInfo
)
{
$arrTraceLines
[]
=
$arrFrameInfo
[
'text'
];
}
$traceText
=
$this
->
limitText
(
implode
(
"
\n
"
,
$arrTraceLines
),
$maxLength
);
$firstAppFrame
=
isset
(
$arrAppFrames
[
0
])
?
$arrAppFrames
[
0
][
'text'
]
:
''
;
return
array
(
'trace'
=>
$traceText
,
'first_app_frame'
=>
$firstAppFrame
,
);
}
private
function
mapTraceFrame
(
array
$arrFrame
,
int
$index
)
:
array
{
$file
=
isset
(
$arrFrame
[
'file'
])
?
(
string
)
$arrFrame
[
'file'
]
:
''
;
$line
=
isset
(
$arrFrame
[
'line'
])
?
(
int
)
$arrFrame
[
'line'
]
:
0
;
$class
=
isset
(
$arrFrame
[
'class'
])
?
(
string
)
$arrFrame
[
'class'
]
:
''
;
$type
=
isset
(
$arrFrame
[
'type'
])
?
(
string
)
$arrFrame
[
'type'
]
:
''
;
$function
=
isset
(
$arrFrame
[
'function'
])
?
(
string
)
$arrFrame
[
'function'
]
:
'unknown'
;
$text
=
sprintf
(
'#%d %s%s%s %s:%d'
,
$index
,
$class
,
$type
,
$function
,
$file
!==
''
?
$file
:
'[internal]'
,
$line
);
return
array
(
'text'
=>
$text
,
'file'
=>
$file
,
'class'
=>
$class
,
);
}
private
function
isAppFrame
(
array
$arrFrameInfo
,
string
$appDir
,
array
$arrClassPrefixes
)
:
bool
{
$file
=
(
string
)
(
$arrFrameInfo
[
'file'
]
??
''
);
$class
=
(
string
)
(
$arrFrameInfo
[
'class'
]
??
''
);
if
(
$file
!==
''
&&
$appDir
!==
''
)
{
$normalizedFile
=
str_replace
(
'\\'
,
'/'
,
$file
);
if
(
strpos
(
$normalizedFile
,
$appDir
.
'/'
)
===
0
||
$normalizedFile
===
$appDir
)
{
return
true
;
}
}
foreach
(
$arrClassPrefixes
as
$prefix
)
{
$prefixText
=
(
string
)
$prefix
;
if
(
$prefixText
!==
''
&&
strpos
(
$class
,
$prefixText
)
===
0
)
{
return
true
;
}
}
return
false
;
}
private
function
selectTraceFramesByMode
(
string
$traceMode
,
array
$arrMappedFrames
,
array
$arrAppFrames
,
array
$arrNonVendorFrames
,
bool
$skipVendor
,
int
$maxLines
)
:
array
{
if
(
$traceMode
===
'app_only'
)
{
return
array_slice
(
$arrAppFrames
,
0
,
$maxLines
);
}
if
(
$traceMode
===
'no_vendor'
)
{
return
array_slice
(
$arrNonVendorFrames
,
0
,
$maxLines
);
}
if
(
$traceMode
===
'class_prefix_only'
)
{
return
array_slice
(
$arrAppFrames
,
0
,
$maxLines
);
}
// smart mode: app frames -> non-vendor frames -> fallback all frames
if
(
$arrAppFrames
!==
array
())
{
return
array_slice
(
$arrAppFrames
,
0
,
$maxLines
);
}
if
(
$skipVendor
&&
$arrNonVendorFrames
!==
array
())
{
return
array_slice
(
$arrNonVendorFrames
,
0
,
$maxLines
);
}
return
array_slice
(
$arrMappedFrames
,
0
,
$maxLines
);
}
private
function
resolveCurrentAction
()
:
string
{
if
(
function_exists
(
'app'
)
&&
app
()
->
runningInConsole
())
{
$arrArgv
=
$_SERVER
[
'argv'
]
??
array
();
return
isset
(
$arrArgv
[
1
])
?
'cli: '
.
trim
((
string
)
$arrArgv
[
1
])
:
'cli: console'
;
}
if
(
!
function_exists
(
'request'
))
{
return
'unknown'
;
}
$request
=
request
();
if
(
$request
===
null
)
{
return
'http'
;
}
return
$request
->
method
()
.
' '
.
$request
->
fullUrl
();
}
private
function
isVendorPath
(
string
$path
,
string
$rootDir
)
:
bool
{
if
(
$path
===
''
)
{
return
false
;
}
$normalizedPath
=
str_replace
(
'\\'
,
'/'
,
$path
);
if
(
$rootDir
===
''
)
{
return
strpos
(
$normalizedPath
,
'/vendor/'
)
!==
false
;
}
return
strpos
(
$normalizedPath
,
$rootDir
.
'/vendor/'
)
===
0
;
}
private
function
makeDecoratedTextWidget
(
string
$topLabel
,
string
$text
)
:
array
{
return
array
(
'decoratedText'
=>
array
(
'topLabel'
=>
$topLabel
,
'text'
=>
$this
->
escapeForGoogleChat
(
$text
),
'wrapText'
=>
true
,
),
);
}
private
function
limitText
(
string
$text
,
int
$maxLength
)
:
string
{
$maxLength
=
max
(
1
,
$maxLength
);
if
(
mb_strlen
(
$text
)
<=
$maxLength
)
{
return
$text
;
}
return
mb_substr
(
$text
,
0
,
$maxLength
)
.
'...'
;
}
private
function
escapeForGoogleChat
(
string
$text
)
:
string
{
return
str_replace
(
array
(
'&'
,
'<'
,
'>'
),
array
(
'&'
,
'<'
,
'>'
),
$text
);
}
private
function
shouldBlockByLoopGuard
(
Throwable
$throwable
,
array
$arrContext
=
array
())
:
bool
{
if
(
!
(
bool
)
config
(
'daito-exception-notifier.loop_guard_enabled'
,
true
))
{
return
false
;
}
if
(
self
::
$isNotifying
)
{
return
true
;
}
if
((
bool
)
config
(
'daito-exception-notifier.loop_guard_skip_if_notifier_in_trace'
,
true
)
&&
$this
->
isNotifierRelatedThrowable
(
$throwable
)
)
{
return
true
;
}
$ttlSeconds
=
max
(
1
,
(
int
)
config
(
'daito-exception-notifier.loop_guard_ttl_seconds'
,
30
));
$fingerprint
=
$this
->
buildExceptionFingerprint
(
$throwable
,
$arrContext
);
if
(
$this
->
isProcessCooldownActive
(
$fingerprint
))
{
return
true
;
}
$this
->
setProcessCooldown
(
$fingerprint
,
$ttlSeconds
);
if
(
!
(
bool
)
config
(
'daito-exception-notifier.loop_guard_use_cache'
,
true
))
{
return
false
;
}
if
(
!
function_exists
(
'cache'
))
{
return
false
;
}
$cacheKeyPrefix
=
(
string
)
config
(
'daito-exception-notifier.loop_guard_cache_prefix'
,
'daito-exception-notifier:loop'
);
$cacheKey
=
$cacheKeyPrefix
.
':'
.
$fingerprint
;
try
{
return
cache
()
->
add
(
$cacheKey
,
1
,
$ttlSeconds
)
===
false
;
}
catch
(
Throwable
$throwable
)
{
return
false
;
}
}
private
function
isNotifierRelatedThrowable
(
Throwable
$throwable
)
:
bool
{
$traceText
=
$throwable
->
getTraceAsString
();
if
(
strpos
(
$traceText
,
'Daito\\Lib\\DaitoExceptionNotifier\\'
)
!==
false
)
{
return
true
;
}
return
strpos
(
$traceText
,
'Daito\\Lib\\DaitoGoogleChat\\'
)
!==
false
;
}
private
function
buildExceptionFingerprint
(
Throwable
$throwable
,
array
$arrContext
=
array
())
:
string
{
$action
=
isset
(
$arrContext
[
'action'
])
?
(
string
)
$arrContext
[
'action'
]
:
$this
->
resolveCurrentAction
();
$text
=
implode
(
'|'
,
array
(
get_class
(
$throwable
),
(
string
)
$throwable
->
getFile
(),
(
string
)
$throwable
->
getLine
(),
(
string
)
$throwable
->
getMessage
(),
$action
,
));
return
sha1
(
$text
);
}
private
function
isProcessCooldownActive
(
string
$fingerprint
)
:
bool
{
$expiresAt
=
self
::
$arrFingerprintCooldowns
[
$fingerprint
]
??
0.0
;
return
$expiresAt
>
microtime
(
true
);
}
private
function
setProcessCooldown
(
string
$fingerprint
,
int
$ttlSeconds
)
:
void
{
self
::
$arrFingerprintCooldowns
[
$fingerprint
]
=
microtime
(
true
)
+
max
(
1
,
$ttlSeconds
);
}
}
src/DaitoExceptionNotifier/Providers/DaitoExceptionNotifierProvider.php
0 → 100644
View file @
9fe3ba3
<?php
namespace
Daito\Lib\DaitoExceptionNotifier\Providers
;
use
Daito\Lib\DaitoExceptionNotifier\DaitoExceptionNotifierManager
;
use
Daito\Lib\DaitoGoogleChat\DaitoGoogleChatManager
;
use
Illuminate\Support\ServiceProvider
;
class
DaitoExceptionNotifierProvider
extends
ServiceProvider
{
public
function
register
()
:
void
{
$this
->
mergeConfigFrom
(
__DIR__
.
'/../config/daito-exception-notifier.php'
,
'daito-exception-notifier'
);
$this
->
app
->
singleton
(
DaitoExceptionNotifierManager
::
class
,
function
(
$app
)
{
return
new
DaitoExceptionNotifierManager
(
$app
->
make
(
DaitoGoogleChatManager
::
class
)
);
});
}
public
function
boot
()
:
void
{
$this
->
publishes
(
array
(
__DIR__
.
'/../config/daito-exception-notifier.php'
=>
config_path
(
'daito-exception-notifier.php'
),
),
'daito-exception-notifier-config'
);
}
}
src/DaitoExceptionNotifier/config/daito-exception-notifier.php
0 → 100644
View file @
9fe3ba3
<?php
return
array
(
'enabled'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_ENABLED'
,
true
),
'send_mode'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_SEND_MODE'
,
'queue'
),
// queue|sync
'card_title'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_CARD_TITLE'
,
'Exception Alert'
),
'loop_guard_enabled'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_ENABLED'
,
true
),
'loop_guard_ttl_seconds'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_TTL_SECONDS'
,
30
),
'loop_guard_use_cache'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_USE_CACHE'
,
true
),
'loop_guard_cache_prefix'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_CACHE_PREFIX'
,
'daito-exception-notifier:loop'
),
'loop_guard_skip_if_notifier_in_trace'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_LOOP_GUARD_SKIP_NOTIFIER_TRACE'
,
true
),
'message_max_length'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_MESSAGE_MAX_LENGTH'
,
1000
),
'trace_mode'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_TRACE_MODE'
,
'smart'
),
// smart|app_only|no_vendor|class_prefix_only
'trace_class_prefixes'
=>
array
(
'App\\'
),
'trace_include_first_app_frame'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_TRACE_INCLUDE_FIRST_APP_FRAME'
,
true
),
'trace_max_lines'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_TRACE_MAX_LINES'
,
8
),
'trace_max_length'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_TRACE_MAX_LENGTH'
,
2500
),
'trace_skip_vendor'
=>
env
(
'DAITO_EXCEPTION_NOTIFIER_TRACE_SKIP_VENDOR'
,
true
),
);
Please
register
or
sign in
to post a comment