77use Monolog \Formatter \LineFormatter ;
88use \Monolog \Logger ;
99use \Monolog \Handler \AbstractProcessingHandler ;
10+ use Psr \Log \LogLevel ;
1011
1112class DiscordHandler extends AbstractProcessingHandler
1213{
13- private $ initialized = false ;
1414 private $ guzzle ;
15-
16- private $ name ;
17- private $ subname ;
18-
15+ private $ suffix ;
1916 private $ webhook ;
20- private $ statement ;
21- private $ roleId ;
22-
23- /**
24- * MonologDiscordHandler constructor.
25- * @param $webhook
26- * @param $name
27- * @param string $subname
28- * @param int $level
29- * @param bool $bubble
30- * @param null $roleId
31- */
32- public function __construct ($ webhook , $ name , $ subname = '' , $ level = Logger::DEBUG , $ bubble = true , $ roleId = null )
17+ private $ message ;
18+ private $ context ;
19+
20+ /**
21+ * MonologDiscordHandler constructor.
22+ * @param array $config
23+ */
24+ public function __construct ($ config )
3325 {
34- $ this ->name = $ name ;
35- $ this ->subname = $ subname ;
26+ $ this ->suffix = $ config ['suffix ' ] ?? '' ;
3627 $ this ->guzzle = new \GuzzleHttp \Client ();
37- $ this ->webhook = $ webhook ;
38- $ this ->roleId = $ roleId ;
39- parent ::__construct ($ level , $ bubble );
28+ $ this ->webhook = $ config ['webhook ' ] ?? false ;
29+ $ this ->message = $ config ['message ' ] ?? false ;
30+ $ this ->context = $ config ['context ' ] ?? false ;
31+ parent ::__construct ($ config ['level ' ] ?? 'debug ' , $ this ->bubble );
32+
4033 }
4134
4235 /**
@@ -45,35 +38,99 @@ public function __construct($webhook, $name, $subname = '', $level = Logger::DEB
4538 */
4639 protected function write ($ record ): void
4740 {
48- $ formatter = new LineFormatter (null , null , true , true );
49- $ formatter ->includeStacktraces ();
50- $ content = $ formatter ->format ($ record );
51-
52- // Set up the formatted log
53- $ log = [
54- 'embeds ' => [
55- [
56- 'title ' => 'Log entry - ' .now ()->format ('d.m.Y H:i:s ' ),
57- // Use CSS for the formatter, as it provides the most distinct colouring.
58- 'description ' => "```css \n" . substr ($ content , 0 , 2030 ). '``` ' ,
59- 'color ' => 0xE74C3C ,
60- ],
61- ],
41+ $ message = new LineFormatter ('%message% ' , null , true , true );
42+ $ message = $ message ->format ($ record );
43+
44+ if ($ this ->context ) {
45+ $ stacktrace = new LineFormatter ('%context% %extra% ' , null , true , true );
46+ $ stacktrace ->includeStacktraces ();
47+ $ stacktrace = $ stacktrace ->format ($ record );
48+ }
49+
50+ // Add emoji based on the error level
51+ switch ($ record ->level ->toPsrLogLevel ()) {
52+ case LogLevel::NOTICE :
53+ $ emoji = ':helicopter: ' ;
54+ break ;
55+ case LogLevel::WARNING :
56+ $ emoji = ':warning: ' ;
57+ break ;
58+ case LogLevel::INFO :
59+ $ emoji = ':information_source: ' ;
60+ break ;
61+ case LogLevel::DEBUG :
62+ $ emoji = ':zap: ' ;
63+ break ;
64+ default :
65+ $ emoji = ':boom: ' ;
66+ break ;
67+ }
68+
69+ // Add fields
70+ $ fields = [];
71+
72+ $ request = request ();
73+
74+ // Add the request url if any
75+ $ request_url = $ request ?->fullUrl() ?? false ;
76+ if ($ request_url && !app ()->runningInConsole ()) {
77+ $ fields [] = [
78+ 'name ' => 'Visited URL ' ,
79+ 'value ' => $ request ?->fullUrl()
80+ ];
81+ }
82+
83+ // Add the logged in user id if any
84+ $ user_id = $ record ->context ['userId ' ] ?? false ;
85+ if ($ user_id ) {
86+ $ fields [] = [
87+ 'name ' => 'User ID ' ,
88+ 'value ' => $ user_id
89+ ];
90+ }
91+
92+ // Add the file path if exception
93+ if (isset ($ record ->context ['exception ' ])) {
94+ $ file_path = $ record ->context ['exception ' ]->getFile () ?? false ;
95+ $ file_line = $ record ->context ['exception ' ]->getLine () ?? 'n/a ' ;
96+
97+ if ($ file_path ) {
98+ $ fields [] = [
99+ 'name ' => 'File path ' ,
100+ 'value ' => '` ' . str ($ file_path )->replace (base_path (), '' ) . '` at line ** ' . $ file_line . '** '
101+ ];
102+ }
103+ }
104+
105+ // Set embeds
106+ $ log ['embeds ' ][] = [
107+ 'title ' => '**[ ' . now ()->format ('d.m.Y H:i:s ' ) . ']** ' .str ($ record ->level ->getName ())->lower ()->ucfirst ().' ' . $ emoji .' ' .$ this ->suffix ,
108+ 'description ' => "```css \n" . str ($ message )->limit ('4000 ' ) . '``` ' ,
109+ 'color ' => 0xE74C3C ,
110+ 'fields ' => $ fields
62111 ];
63112
64- // Tag a role if configured for it
65- if ($ this ->roleId ) $ log ['content ' ] = "<@& " . $ this ->roleId . "> " ;
66-
67- if ($ this ->webhook ) {
68- try {
69- // Send it to discord
70- $ this ->guzzle ->request ('POST ' , $ this ->webhook , [
71- RequestOptions::JSON => $ log ,
72- ]);
73- } catch (\Exception $ e ) {
74- //silently fail
75- }
76- }
113+ // Add full context
114+ if ($ this ->context === true && $ stacktrace ) {
115+ $ log ['embeds ' ][] = [
116+ 'title ' => 'Full context ' ,
117+ 'description ' => "```css \n" . str ($ stacktrace )->limit ('4000 ' ) . '``` ' ,
118+ 'color ' => 0xE74C3C ,
119+ ];
120+ }
121+
122+ // Add custom message
123+ if ($ this ->message ) $ log ['content ' ] = $ this ->message ;
124+
125+ if ($ this ->webhook ) {
126+ try {
127+ // Send it to discord
128+ $ this ->guzzle ->request ('POST ' , $ this ->webhook , [
129+ RequestOptions::JSON => $ log ,
130+ ]);
131+ } catch (\Exception $ e ) {
132+ //silently fail better than killing the whole app
133+ }
134+ }
77135 }
78136}
79-
0 commit comments