-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathiobroker_logfile-script.js
1966 lines (1700 loc) · 95.9 KB
/
iobroker_logfile-script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*************************************************************************************************************************
* ---------------------------
* Log Script für ioBroker zum Aufbereiten des Logs für Visualisierungen (vis), oder um
* auf Log-Ereignisse zu reagieren.
* ---------------------------
*
* Das Script nimmt jeden neuen Logeintrag des ioBrokers und wendet entsprechend gesetzte
* Filter an, um den Eintrag dann in den entsprechenden Datenpunkten dieses Scripts abzulegen.
* Es stehen auch JSON-Datenpunkte zur Verfügung, mit diesen kann im vis eine
* Tabelle ausgegeben werden (z.B. über das Widget 'basic - Table' oder 'materialdesign - Table').
*
* Aktuelle Version: https://github.com/Mic-M/iobroker.logfile-script
* Support: https://forum.iobroker.net/topic/13971/vorlage-log-datei-aufbereiten-f%C3%BCr-vis-javascript
* Autor: Mic (ioBroker) | Mic-M (github)
* -----------------------------------------------------------------------------------------------------------------------
* VORAUSSETZUNGEN
* 1.) Nur falls Datenpunkte unterhalb '0_userdata.0' abgelegt werden sollen:
* In der Instanz des JavaScript-Adapters die Option [Erlaube das Kommando "setObject"] aktivieren.
* Siehe auch: https://github.com/Mic-M/iobroker.createUserStates
* 2.) Dieses Script benötigt die JavaScript-Adapter-Version 4.3.0 (2019-10-09) oder höher.
* Wer eine ältere Version einsetzt: Bitte Script-Version 2.0.2 verwenden.
* =====================================================================================
* -----------------------------------------------------------------------------------------------------------------------
* Change Log:
* 4.10.1 Mic - Fix: eliminate undefined strings in JSON if JSON_APPLY_CSS = false
* 4.10 Mic + JSON: add support for individual items in column provided through log. See
* 4.9 Mic + Add "Heute"/"Gestern" (today/yesterday) option for dates in JSON output instead of actual date
* - Fix: jsonDateFormat: correction of month/minute. Month/Day/Year (mm/dd/yy/yyyy) now require lower case
* letters, Hour/Minute/Second (HH/MM/SS) upper case letters to differenciate month (mm) vs. minute (MM)
* 4.8 Mic + Allow regular expressions in BLACKLIST_GLOBAL
* + Allow regular expressions in LOG_FILTER: 'blacklist', 'clean', 'filter_all', 'filter_any'
* - Fix: Log line regex, which did not allow upper case letters in host (source)
* 4.7 Mic - Fixed issue if NUMBER_OF_VIS_VIEWS = 0
* 4.6 Mic - Pushing 'Log-Script.visView1.clearJSON' will update timestamp of 'Log-Script.logXXX.clearJSON'.
* See: https://forum.iobroker.net/post/375932
* 4.5.0 Mic * Simply moved 4.5Alpha into 4.5.0 due to successful user tests. No code changes since 4.5Alpha.
* 4.5Alpha Mic + Add new states '.All.visViewX' to switch between JSON tables in VIS.
* + Add new state '.All.clearAllJSON' to clear all JSON logs of all defined filters at once.
* + Add new state '.All.kastTimeUpdated' to provide the time of the last update (schedule)
* of the script in a state for Visualization.
* 4.0.1 Mic - Add "jsonDateFormat: 'dd.mm. hh:mm'," to FILTER_LOG, id 'all'.
* 4.0 Mic + To allow individual settings per each defined LOG_FILTER, the following global
* settings were moved to LOG_FILTER:
* * JSON_DATE_FORMAT -> jsonDateFormat
* * JSON_LEN -> jsonLogLength
* * JSON_NO_ENTRIES -> jsonMaxLines
* * JSON_APPLY_CSS_LIMITED_TO_LEVEL -> jsonCssToLevel
* * L_SORT_ORDER_DESC -> sortDescending
* + Code improvements
* + Renamed LOG_NO_OF_ENTRIES to MAX_LOG_LINES
* ----------------------------------------------------------------------------------------------------
* 3.4 Mic + Support both '0_userdata.0' and 'javascript.x' for state creation
* 3.3 Mic - Fix state path
* 3.2 Mic + Create all states under 0_userdata.0, and no longer under javascript.<instance> (like javascript.0)
* 3.1 Mic + Change to stable as tests were successful
* + Add new option REMOVE_PID: The js-controller version 2.0+ adds the PID number inside brackets
* to the beginning of the message. Setting REMOVE_PID = false will remove it.
* 3.0Alpha Mic + Major Change: JavaScript adapter 4.3+ now provides onLog() function:
* https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#onlog
* We are using this new function to streamline this log script tremendously and to remove node-tail.
* ----------------------------------------------------------------------------------------------------
* 2.0.2 Mic + Changed certain functions to async to get rid of setTimout() and for the sake of better error handling.
* + startTailingProcess(): ensure the tailing starts if the file is present (wait to be created)
* 2.0.1a Mic Removed constant MERGE_LOGLINES_ACTIVE
* 2.0.0a Mic Major improvements and fixes:
* + Change from instant state update to schedule (STATE_UPDATE_SCHEDULE). The instant update, so once
* new log entries coming in, caused several issues (setting and getting state values (getState() and
* setState()) within <1ms simply does not work.
* - Fix issue with merging log lines
* + Moved global option MERGE_LOGLINES_ACTIVE to LOG_FILTER, for allowing turning on/off for each filter id.
* + Several other code improvements
* Note: For upgrading from previous version: replace script entirely, re-enter all your options,
* and delete all existing states prior to first activation of this script.
* ----------------------------------------------------------------------------------------------------
* 1.5.1 Mic - Set option MERGE_LOGLINES_ACTIVE to 'false' as default, as users reported issues. See
* https://forum.iobroker.net/post/288772 . Also option MERGE_LOGLINES_ACTIVE being marked as "experimental"
* in the comments. Requires further investigation.
* 1.5 Mic - Fix issue with option MERGE_LOGLINES_ACTIVE
* 1.4 Mic + New option MERGE_LOGLINES_TXT for an individual (e.g. localized) string other than 'entries'.
- Fix JSON span class closing
* 1.3 Mic + New option MERGE_LOGLINES_ACTIVE: Merge Loglines with same log message to only one line and adds leading
* '[123 entries]' to log message.
* 1.2 Mic - Fixed issue #6 (Button javascript.0.Log-Script.logXxxx.clearJSON not working reliably)
* 1.1 Mic + 1. 1.0x script seems to work reliable per user feedback and my own test, so pushing into 1.1 stable.
* + New state '.logMostRecent': provides just the most recent log entry to work with "on /
* subscribe" on this state and trigger actions accordingly.
* 1.02 alpha Mic - fix restarting at 0:00 (note: restarting is needed due to log file name change)
* 1.01 alpha Mic - fix: creating new file system log file only if not yet existing
* 1.00 alpha Mic + Entirely recoded to implement node-tail (https://github.com/lucagrulla/node-tail).
* ----------------------------------------------------------------------------------------------------
* 0.8.1 Mic - Fix: L_SORT_ORDER_DESC was not defined (renamed constant name was not changed in config)
* 0.8 Mic - Fix: Script caused a "file not found" error if executed right at or shortly after midnight.
* 0.7 Mic - Fix: States "...clearDateTime" will not get an initial date value on first script start,
* also fix for "on({id: ".
* 0.6 Mic + Put 0.5.1 BETA into stable
* + New option L_APPLY_CSS. If true, it will add <span class='log-info'>xxx</span>
* to each log string. 'log-info' for level info, 'log-error' for error, etc.
* This makes it easy to format a JSON table with CSS.
* 0.5.1 BETA Mic + New States "Clear JSON log ..." and "Clear JSON log - Date/Time ...".
* When the button "Clear JSON log" is pushed, the current date/time
* will be set into the date/time state. Once refreshed
* (per schedule in the script, e.g. after 2 minutes), the JSON
* will be cleaned and display just newer logs.
* Use Case: In vis, you can now add a button "clear log" or
* "Mark as read". If you hit the button, the log will be
* cleared and just new log items will be displayed.
* *** THIS IS STILL BEING TESTED *** therefore a beta release...
* 0.5 Mic + New parameter 'clean' to remove certain strings
* from the log line.
* + New parameter 'columns' for JSON output to specify which columns
* to be shown, and in which order.
* + New state "JSONcount" to have the number of log lines in state
* - Fixed a few issues
* 0.4 Mic - Bug fix: improved validation of log line consistency
* 0.3 Mic + Added filtering and blacklist
* - Several fixes
* 0.2 Mic - Bug fix: corrected wrong function name
* 0.1 Mic * Initial release
************************************************************************************************************************/
/*******************************************************************************
* Konfiguration: Pfade
******************************************************************************/
// Pfad, unter dem die States (Datenpunkte) in den Objekten angelegt werden.
// Es wird die Anlage sowohl unterhalb '0_userdata.0' als auch 'javascript.x' unterstützt.
const LOG_STATE_PATH = '0_userdata.0.Log-Script';
// Pfad zum Log-Verzeichnis auf dem Server.
// Standard-Pfad unter Linux: '/opt/iobroker/log/'. Wenn das bei dir auch so ist, dann einfach belassen.
const LOG_FS_PATH = '/opt/iobroker/log/';
/*******************************************************************************
* Konfiguration: Alle Logeinträge - Global
******************************************************************************/
// Zahl: Maximale Anzahl der letzten Logeinträge in den Datenpunkten. Alle älteren werden entfernt.
// Bitte nicht allzu viele behalten, denn das kostet Performance.
const MAX_LOG_LINES = 100;
// Der js-Controller Version 2.0 oder größer fügt Logs teils vorne die PID in Klammern hinzu,
// also z.B. "(12234) Terminated (15): Without reason".
// Mit dieser Option lassen sich die PIDs aus den Logzeilen entfernen.
const REMOVE_PID = true;
/**
* Schwarze Liste (Black list)
* Falls einer dieser Satzteile/Begriffe in einer Logzeile enthalten ist, dann wird der Log-Eintrag
* komplett ignoriert, egal was weiter unten eingestellt wird.
* Dies dient dazu, um penetrante Logeinträge gar nicht erst zu berücksichtigen.
* Bitte beachten:
* 1. Es ist sowohl String als auch Regex erlaubt. Falls String: es wird auf teilweise Übereinstimmung geprüft.
* 2. Bestehende Datenpunkt-Inhalte dieses Scripts bei Anpassung dieser Option werden nicht nachträglich neu gefiltert,
* sondern nur alle neu hinzugefügten Log-Einträge ab Speichern des Scripts werden berücksichtigt.
*/
const BLACKLIST_GLOBAL = [
'<==Disconnect system.user.admin from ::ffff:', // web.0 Adapter
/registered [0-9]+ subscriptions and [0-9]+ schedules/, // Beispiel für Regex
/instance system\.adapter\.[^\s]* terminated with code 0 \((NO_ERROR|OK)\)/, // Weiteres Regex-Beispiel
/instance system\.adapter\.[^\s]* started with pid [0-9]+/, // Noch ein Regex
'Start javascript script.js.',
'Stop script script.js.',
'bring.0 Cannot get translations: RequestError',
' reconnected. Old secret ', // Sonoff
'Popup-News readed...', // info.0 Adapter
'[warn] Projects disabled : set editorTheme.projects.enabled=true to enable', // see https://forum.iobroker.net/topic/12260/
'[warn] Projects disabled : editorTheme.projects.enabled=false',
'Update repository "latest" under',
];
/**
* Zusatz-Einstellung für Option "merge" für LOG_FILTER (unter "Konfiguration: Datenpunkte und Filter"):
* In MERGE_LOGLINES_TXT kann hier ein anderes Wort eingetragen werden, z.B. 'entries' oder 'Zeilen', damit [123 entries]
* oder [123 Zeilen] vorangestellt wird anstatt [123 Einträge].
* HINWEIS: Falls MERGE_LOGLINES_TXT geändert wird: bitte alle Datenpunkte des Scripts löschen und dann Script neu starten.
*/
const MERGE_LOGLINES_TXT = 'Einträge';
/**
* Für JSON-Tabelle: Füge CSS-Klasse hinzu je nach Log-Level (debug, silly, info, warn und error), um Tabellen-Text zu formatieren.
* Beispiel für Log-Level "debug": ersetzt "xxx" durch "<span class='log-debug'>xxx</span>""
* Es wird jeweils "log-" vorangestellt, also: debug -> log-debug, silly -> log-silly, info -> log-info, etc.
* Etwa für Widget "basic - Table" im vis können im Reiter "CSS" z.B. folgende Zeilen hinzugefügt werden,
* um Warnungen in oranger und Fehler in roter Farbe anzuzeigen.
* .log-warn { color: orange; }
* .log-error { color: red; }
* Tipp: In LOG_FILTER kann dann bei den einzelnen Filtern mittels "jsonCssToLevel" eingestellt werden, dass das CSS
* nur für die Spalte "level" (also debug, error, info) und nicht auf alle Spalten angewendet wird.
*/
const JSON_APPLY_CSS = true;
/*******************************************************************************
* Konfiguration: Datenpunkte und Filter
******************************************************************************
* Dies ist das Herzstück dieses Scripts: hier werden die Datenpunkte konfiguriert, die erstellt werden sollen.
* Hierbei kannst du entsprechend Filter setzen, also z.B. Wörter/Begriffe, die in Logeinträgen enthalten sein
* müssen, damit sie in den jeweiligen Datenpunkten aufgenommen werden.
* --------------------------------------------------------------------------------------------------------------------------
* id: Ein Begriff ohne Leerzeichen, z.B. "error", "sonoff", homematic, etc. Die ID wird dann Teil der
* Datenpunkte, z.B. "javascript.0.Log-Script.logHomematic.log" mit automatisch vorangestelltem "log".
* --------------------------------------------------------------------------------------------------------------------------
* filter_all: ALLE Begriffe müssen in der Logzeile enthalten sein. Ist einer der Begriffe nicht enthalten, dann wird der
* komplette Logeintrag auch nicht übernommen. Leeres Array [] eingeben, falls hier filtern nicht gewünscht.
* Es ist auch Regex erlaubt.
* --------------------------------------------------------------------------------------------------------------------------
* filter_any: Mindestens einer der gelisteten Begriffe muss enthalten sein. Leeres Array [] eingeben, falls hier filtern
* nicht gewünscht.
* Es ist auch Regex erlaubt.
* --------------------------------------------------------------------------------------------------------------------------
* blacklist: Schwarze Liste: Wenn einer dieser Begriffe im Logeintrag enthalten ist, so wird der komplette Logeintrag
* nicht übernommen, egal was vorher in filter_all oder filter_any definiert ist.
* HINWEIS: BLACKLIST_GLOBAL wird vorher schon angewendet, hier kannst du einfach nur noch eine individuelle
* Blackliste pro id definieren.
* Es ist auch Regex erlaubt.
* --------------------------------------------------------------------------------------------------------------------------
* clean: Der Log-Eintrag wird um diese Zeichenfolgen bereinigt, d.h. diese werden entfernt, aber die restliche Zeile
* bleibt bestehen. Z.B. um unerwünschte Zeichenfolgen zu entfernen oder Log-Ausgaben zu kürzen.
* Es ist auch Regex erlaubt.
* --------------------------------------------------------------------------------------------------------------------------
* merge: Log-Einträge mit gleichem Text zusammenfassen. Beispiel:
* -----------------------------------------------------------------------------------
* 2019-08-17 20:00:00.335 - info: javascript.0 script.js.Wetter: Wetterdaten abrufen.
* 2019-08-17 20:15:00.335 - info: javascript.0 script.js.Wetter: Wetterdaten abrufen.
* 2019-08-17 20:30:00.335 - info: javascript.0 script.js.Wetter: Wetterdaten abrufen.
* -----------------------------------------------------------------------------------
* Daraus wird dann nur noch eine Logzeile mit letztem Datum/Uhrzeit und hinzufügen von "[3 Einträge]":
* -----------------------------------------------------------------------------------
* 2019-08-17 20:30:00.335 - info: javascript.0 [3 Einträge] script.js.Wetter: Wetterdaten abrufen.
* -----------------------------------------------------------------------------------
* Zum aktivieren: true eintragen, zum deaktivieren: false eintragen.
* --------------------------------------------------------------------------------------------------------------------------
* sortDescending: Wenn true: Sortiert die Logeinträge absteigend, also neuester oben.
* Wenn false: Sortiert die Logeinträge aufsteigend, also ältester oben.
* --------------------------------------------------------------------------------------------------------------------------
* jsonColumns: Nur für JSON (für vis).
* Folgende Spalten gibt es: 'date','level','source','msg'. Hier können einzelne Spalten entfernt oder die
* Reihenfolge verändert werden. Bitte keine anderen Spalten eintragen, sondern nur 'date','level','source','msg'.
* --------------------------------------------------------------------------------------------------------------------------
* jsonDateFormat: Datumsformat für JSON Log. Z.B. volles Datum mit 'YYYY-MM-DD hh:mm:ss' oder nur Uhrzeit mit "hh:mm:ss". Die
* Platzhalter YYYY, MM, DD usw. werden jeweils ersetzt.
* YYYY = Jahr 4stellig (z.B. 2019), MM = Jahr 2stellig (z.B. 20), MM = Monat, DD = Tag, hh = Stunde, mm = Minute,
* ss = Sekunde. Auf Groß- und Kleinschreibung achten!
* Die Verbinder (-, :, Leerzeichen, etc.) können im Prinzip frei gewählt werden.
* Beispiele: 'hh:mm:ss' für 19:37:25, 'hh:mm' für 19:37, 'DD.MM. hh:mm' für '25.07. 19:37'
* --- Neu seit Script-Version 4.9:
* Wenn das Datum in "Hash-Zeichen (Raute = #)" gesetzt wird, dann wird es durch "Heute" bzw. "Gestern"
* ersetzt. Beispiele:
* - Aus '#DD.MM.# hh:mm' wird 'Heute 20:35', falls der Log von heute ist.
* - Aus '#DD.MM.YYYY# hh:mm' wird 'Gestern 20:35', falls der Log von gestern ist.
* - Aus '#DD.MM.YYYY# hh:mm' wird '18.02. 20:35', falls der Log nicht von heute oder gestern ist.
* - Aus '#DD.MM.YY# hh:mm' wird '18.02.20 20:35', falls der Log nicht von heute oder gestern ist.
* --------------------------------------------------------------------------------------------------------------------------
* jsonLogLength: Maximale Anzahl Zeichen jeder einzelnen Log-Meldung im JSON-Log. Alles was länger ist, wird abgeschnitten.
* --------------------------------------------------------------------------------------------------------------------------
* jsonMaxLines: Maximale Anzahl der letzten Logeinträge im JSON-Log. Alle älteren werden entfernt.
* Falls in MAX_LOG_LINES z.B. "100" gesetzt wird, wird hier bei 100 der Cut gemacht, selbst wenn in
* jsonMaxLines etwa 250 eingetragen wird. D.h. im Bedarf zuerst MAX_LOG_LINES anpassen/erhöhen.
* --------------------------------------------------------------------------------------------------------------------------
* jsonCssToLevel: Wenn true, dann wird JSON_APPLY_CSS nur für die Spalte "level" (also debug, error, info) angewendet,
* aber nicht für die restlichen Spalten wie Datum, Log-Eintrag, etc.
Falls alle Spalten das CSS bekommen sollen: auf false setzen.
* --------------------------------------------------------------------------------------------------------------------------
*
* WEITERER HINWEIS:
* Bestehende Datenpunkt-Inhalte dieses Scripts bei Anpassung dieser Option werden nicht nachträglich neu
* gefiltert, sondern nur alle neu hinzugefügten Log-Einträge ab Speichern des Scripts werden berücksichtigt.
* --------------------------------------------------------------------------------------------------------------------------
*/
const LOG_FILTER = [
// Beispiel für individuellen Eintrag. Hier wird euer Hubschrauber-Landeplatz überwacht :-) Wir wollen nur Einträge
// vom Adapter 'hubschr.0'. Dabei sollen entweder Wetterwarnungen, Alarme, oder UFOs gemeldet werden. Alles unter
// Windstärke "5 Bft" interessiert uns dabei nicht, daher haben wir '0 Bft' bis '4 Bft' auf die Blackliste gesetzt.
// Außerdem entfernen wir von der Log-Zeile die Zeichenfolgen '****', '!!!!' und 'ufo gesichtet', der Rest bleibt
// aber bestehen. Zudem haben wir unter jsonColumns die Spaltenreihenfolge geändert. 'level' herausgenommen, und Quelle
// ganz vorne.
/*
{
id: 'hubschrauberlandeplatz',
filter_all: ['hubschr.0'],
filter_any: ['wetterwarnung', 'alarm', 'ufo'],
blacklist: ['0 Bft', '1 Bft', '2 Bft', '3 Bft', '4 Bft'],
clean: ['****', '!!!!', 'ufo gesichtet'],
merge: true,
sortDescending: true,
jsonDateFormat: '#DD.MM.# hh:mm',
jsonColumns: ['source','date','msg'],
jsonLogLength: 100,
jsonMaxLines: 10,
jsonCssToLevel: true,
},
*/
/*
{
id: 'all', // Beispiel "all": hier kommen alle Logeinträge rein, keine Filterung
filter_all: ['', ''], // wird ignoriert, wenn leer
filter_any: ['', ''], // wird ignoriert, wenn leer
blacklist: ['', ''], // wird ignoriert, wenn leer
clean: ['', '', ''], // wird ignoriert, wenn leer
merge: true,
sortDescending: true,
jsonDateFormat: '#DD.MM.# hh:mm',
jsonColumns: ['date','level','source','msg'], // Spaltenreihenfolge für JSON (Tabelle in vis)
jsonLogLength: 100,
jsonMaxLines: 10,
jsonCssToLevel: true,
},
*/
{
id: 'info',
filter_all: [' - info: '], // nur Logeinträge mit Level 'info'
filter_any: ['', ''],
blacklist: [/##\{\s?\".*\"\s?\}##/, ''],
clean: [/script\.js\.[^:]*: /, ''],
merge: true,
sortDescending: true,
jsonDateFormat: '#DD.MM.# hh:mm',
jsonColumns: ['date','level','source','msg'],
jsonLogLength: 100,
jsonMaxLines: 100,
jsonCssToLevel: true,
},
{
id: 'warn',
filter_all: [' - warn: ', ''], // nur Logeinträge mit Level 'warn'
filter_any: [''],
blacklist: ['', '', ''],
clean: [/script\.js\.[^:]*: /, '', ''],
merge: true,
sortDescending: true,
jsonColumns: ['date','level','source','msg'],
jsonDateFormat: '#DD.MM.# hh:mm',
jsonLogLength: 100,
jsonMaxLines: 100,
jsonCssToLevel: true,
},
{
id: 'error',
filter_all: [' - error: ', ''], // nur Logeinträge mit Level 'error'
filter_any: [''],
blacklist: ['', '', ''],
clean: [/script\.js\.[^:]*: /, '', ''],
merge: true,
sortDescending: true,
jsonColumns: ['date','level','source','msg'],
jsonDateFormat: '#DD.MM.# hh:mm',
jsonLogLength: 100,
jsonMaxLines: 100,
jsonCssToLevel: true,
},
{
id: 'warnanderror',
filter_all: ['', ''],
filter_any: [' - error: ', ' - warn: '], // nur Logeinträge mit Levels 'warn' und 'error'
blacklist: ['no playback content', 'Ignore! Actual secret is '],
clean: [/script\.js\.[^:]*: /, '', ''],
merge: true,
sortDescending: true,
jsonDateFormat: '#DD.MM.# hh:mm',
jsonColumns: ['date','level','source','msg'],
jsonLogLength: 100,
jsonMaxLines: 100,
jsonCssToLevel: true,
},
{
// Beispiel, um Adapter zu überwachen.
// Hier werden alle Fehler und Warnungen der Homematic-Adapters hm-rpc.0 und hm-rega.0 gelistet.
id: 'homematic',
filter_all: [/hm-(rpc|rega)\.[0-9]/],
filter_any: [' - error: ', ' - warn: ', ' - info: '], // entweder error oder warn
blacklist: ['', '', ''],
clean: ['', '', ''],
merge: true,
sortDescending: true,
jsonDateFormat: '#DD.MM.# hh:mm',
jsonColumns: ['date','level','source','msg'],
jsonLogLength: 100,
jsonMaxLines: 100,
jsonCssToLevel: true,
},
];
/*******************************************************************************
* Optionale Konfiguration: Auswahl Log-Filter für VIS unterhalb ".All"
******************************************************************************/
// Wenn man in VIS eine Tabelle der Logs ausgibt, kann man hiermit mit Buttons
// ('Homematic', 'Warnungen', 'Fehler' usw. zwischen den einzelnen Filtern umschalten,
// die dann dynamisch jeweils in dieser einen Tabelle ausgegeben werden.
// Hier die Anzahl der unterschiedlichen VIS-Views angeben, in denen du das brauchst.
// Diese werden angelegt unter '.All.visView1', '.All.visView2', usw.
// Falls auf 0 gestellt, dann werden gar keine Datenpunkte ausgegeben.
const NUMBER_OF_VIS_VIEWS = 1;
/*******************************************************************************
* Konfiguration: Konsolen-Ausgaben
******************************************************************************/
// Auf true setzen, wenn zur Fehlersuche einige Meldungen ausgegeben werden sollen.
// Ansonsten bitte auf false stellen.
const SCRIPT_DEBUG = false;
// Auf true setzen, wenn ein paar Infos dieses Scripts im Log ausgegeben werden dürfen, bei false bleiben die Infos komplett weg.
const LOG_INFO = true;
/*******************************************************************************
* Experten-Konfiguration
******************************************************************************/
// Wie oft Datenpunkte aktualisieren?
// Neu reinkommende Logeinträge werden erst mal gesammelt (in Variable G_NewLogLinesArrayToProcess). Diese werden dann
// regelmäßig in den Datenpunkten geschrieben. Sinnvoll ist hier nicht kürzer als 2-3 Sekunden, und nicht länger als
// ein paar Minuten. Zu kurzes Intervall: Script kommt nicht mehr nach. Zu lange: falls viele Logeinträge reinkommen,
// kann sich vieles "aufstauen" zur Abarbeitung. Benutze den "Cron"-Button oben rechts für komfortable Einstellung.
const STATE_UPDATE_SCHEDULE = '*/20 * * * * *'; // alle 20 Sekunden
// JSON-Tabelle: ersetze heutiges und gestriges Datum durch 'Heute' bzw. 'Gestern'.
// Mittels Hash-Zeichen(#) kann in LOG_FILTER in der Option "jsonDateFormat" definiert werden,
// dass heutiges und gestriges Datum durch 'Heute' bzw. 'Gestern' ersetzt wird.
// Hier können andere Begriffe statt "Heute"/"Gestern" definiert werden.
const TXT_TODAY = 'Heute';
const TXT_YESTERDAY = 'Gestern';
// Leer lassen! Nur setzen, falls ein eigener Filename für das Logfile verwendet wird für Debug.
const DEBUG_CUSTOM_FILENAME = '';
// Debug: Ignore. Wenn dieses String in der Logzeile enthalten ist, dann ignorieren wir es.
// Dient dazu, dass wir während des Scripts ins Log schreiben können, ohne dass das dieses Script berücksichtigt.
const DEBUG_IGNORE_STR = '[LOGSCRIPT_IGNORE]'; // Muss ein individuelles String sein. Sonst gibt es ggf. eine Endlos-Schleife.
// Debug: Prüfen, ob jede Logzeile erfasst wird, in dem wir diese direkt danach noch mal ins Log schreiben.
// Bitte nur auf Anweisung vom Entwickler einschalten. Sonst wird jeder Logeintrag noch einmal wiederholt,
// mit führendem DEBUG_EXTENDED_STR am Anfang und max. DEBUG_EXTENDED_NO_OF_CHARS an Anzahl Zeichen.
const DEBUG_EXTENDED = false;
const DEBUG_EXTENDED_STR = '[LOGSCRIPT_DEBUG_EXTENDED]'; // Muss ein individuelles String sein. Sonst gibt es ggf. eine Endlos-Schleife.
const DEBUG_EXTENDED_NO_OF_CHARS = 120;
/*************************************************************************************************************************
* Ab hier nichts mehr ändern / Stop editing here!
*************************************************************************************************************************/
/*************************************************************************************************************************
* Global variables and constants
*************************************************************************************************************************/
// Final state path
const FINAL_STATE_LOCATION = validateStatePath(LOG_STATE_PATH, false);
const FINAL_STATE_PATH = validateStatePath(LOG_STATE_PATH, true);
// Regex für die Aufteilung des Logs in 1-Datum/Zeit, 3-Level, 5-Quelle und 7-Logtext.
// Ggf. anzupassen bei anderem Datumsformat im Log. Wir erwarten ein Format
// wie z.B.: '2018-07-22 12:45:02.769 - info: javascript.0 Stop script script.js.ScriptAbc'
// Da als String, wurden alle Backslashes "\" mit einem zweiten Backslash escaped.
const LOG_PATT = '([0-9_.\\-:\\s]*)(\\s+\\- )(silly|debug|info|warn|error|)(: )([^\\s]*)(\\s)(.*)';
// Final number of VIS states. We do not allow more than 9.
function finalVisStatesQty(qty) {
let result = 0;
if( (!isLikeEmpty(qty)) && (qty > 0) ) {
if(qty > 9) {
result = 9;
} else {
result = qty;
}
}
return result;
};
const FINAL_NUM_OF_VIS_VIEWS = finalVisStatesQty(NUMBER_OF_VIS_VIEWS);
// Merge loglines: define pattern (and escape the merge text)
// We added an additional backslash '\' to each backslash as these need to be escaped.
const MERGE_REGEX_PATT = '^\\[(\\d+)\\s' + escapeRegExp(MERGE_LOGLINES_TXT) + '\\]\\s(.*)';
// Log Handler variable for ioBroker function onLog()
let G_LogHandler; // being set later
// Schedule for logfile update
let G_Schedule_StateUpdate; // being set later
// Schedule for midnight JSON update
let G_Schedule_JsonUpdate; // being set later
// We add here all the new log lines to be processed regularly (per STATE_UPDATE_SCHEDULE);
let G_NewLogLinesArrayToProcess = [];
/*************************************************************************************************************************
* init - This is executed on every script (re)start.
*************************************************************************************************************************/
init();
function init() {
// Unsubscribe log handler
onLogUnregister(G_LogHandler);
// Create script states
createLogScriptStates(function() { // force = false
// -- All states created, so we continue by using callback
// Subscribe on changes: Pressed button "clearJSON"
subscribeClearJson();
// Subscribe to log handler
G_LogHandler = onLog('*', data => { // please ignore the red squiggly underline under '*', see Github issue: https://github.com/ioBroker/ioBroker.javascript/issues/457
processNewLogLine(data);
});
// Schedule writing changes into states
clearSchedule(G_Schedule_StateUpdate);
G_Schedule_StateUpdate = schedule(STATE_UPDATE_SCHEDULE, processNewLogsPerSchedule);
// Schedule midnight Json update (due to "Heute"/"Gestern" in date)
clearSchedule(G_Schedule_JsonUpdate);
G_Schedule_JsonUpdate = schedule('1 0 * * *', function() { // Um 00:01 jeden Tag
processLogArrayAndSetStates([], true); // update JSON only
});
// Subscribe to clear all states
stateSubscribeClearAllJSON()
// Subscribe to states for the VIS views
if(FINAL_NUM_OF_VIS_VIEWS > 0) {
stateSubscribeVisWhichFilter(); // which Filter
stateSubscribeVisClearJson(); // clear JSON
}
// Message
if (LOG_INFO) log('Start monitoring of the ioBroker log...', 'info');
// Update JSON
setTimeout(function(){
processLogArrayAndSetStates([], true); // update JSON only
}, 5000);
});
}
function processNewLogLine(data) {
// Convert to Log Line
// TODO: This is a quick implementation of new function onLog().
// We need to entirely rewrite script later to fully use the data object.
// However, at this time, we convert it to a standard log line being expected.
// First, remove PID if desired
let msg = data.message;
if (REMOVE_PID) msg = removePID(msg);
// Now convert to log line
let newLogEntry = timestampToLogDate(data.ts) + ' - [32m' + data.severity + '[39m: ' + msg;
// Check if we have DEBUG_IGNORE_STR in the new log line
if(! newLogEntry.includes(DEBUG_IGNORE_STR)) {
if (newLogEntry.length > 45) { // a log line with less than 45 chars is not a valid log line.
// Cleanse and apply blacklist
newLogEntry = cleanseLogLine(newLogEntry);
// some debugging
// Important: You will need to change onLog('*') to a certain severity so that this will work.
// See onLog() Documentation: "Important: you cannot output logs in handler with the same severity to avoid infinite loops."
if (SCRIPT_DEBUG) log(DEBUG_IGNORE_STR + '===============================================================', 'warn');
if (SCRIPT_DEBUG) log(DEBUG_IGNORE_STR + 'New Log Entry, Len (' + newLogEntry.length + '), content: [' + newLogEntry + ']', 'warn');
// Push result into logArrayFinal
G_NewLogLinesArrayToProcess.push(newLogEntry);
// This is for debugging purposes, and it will log every new log entry once again. See DEBUG_EXTENDED option above.
if (DEBUG_EXTENDED) {
if (! newLogEntry.includes(DEBUG_EXTENDED_STR)) { // makes sure no endless loop here.
log(DEBUG_EXTENDED_STR + newLogEntry.substring(0, DEBUG_EXTENDED_NO_OF_CHARS));
}
}
}
}
}
/**
* Called per schedule STATE_UPDATE_SCHEDULE.
* It processes G_NewLogLinesArrayToProcess
*/
function processNewLogsPerSchedule() {
if (! isLikeEmpty (G_NewLogLinesArrayToProcess) ) {
// We use array spreads '...' to copy array. If not, array is changed by reference and not value.
// That means, if we change the target array, it will also change the source array.
// See https://stackoverflow.com/questions/7486085/copy-array-by-value
let logArrayToProcess = [...G_NewLogLinesArrayToProcess];
G_NewLogLinesArrayToProcess.length = 0; // emptying array. https://stackoverflow.com/questions/4804235/difference-between-array-length-0-and-array
/**
* Apply the filters as set in LOG_FILTER and split up log levels into elements of an array
* logArrayToProcessFiltered will look as follows:
* logArrayToProcessFiltered = [
* ['info':'15.08.2019 09:27:55.476 info adapt.0 some log', 'error':''],
* ['info':'15.08.2019 09:33:58.522 info adapt.0 some more log', 'error':''],
* ['info':'', 'error':'15.08.2019 09:37:55.807 error adapt.0 some error log']
* ]
*/
let logArrayToProcessFiltered = [];
for (let lpEntry of logArrayToProcess) {
let logEntryFilteredArray = applyFilter(lpEntry);
logArrayToProcessFiltered.push(logEntryFilteredArray);
}
// Further process and finally set states with our results.
processLogArrayAndSetStates(logArrayToProcessFiltered);
}
// Finally, set updatestate with current date/time
setState(FINAL_STATE_PATH + '.All.lastTimeUpdated', Date.now());
}
/*************************************************************************************************************************
* Filtering
*************************************************************************************************************************/
/**
* This function applies the filters as set in LOG_FILTER.
* Also, it splits up the log levels into elements of an array we return by this function.
* @param {string} strLogEntry
* @return {array} split up log levels as elements within this array, like: ['info':'logtext', 'error':'logtext'] etc.
*/
function applyFilter(strLogEntry) {
// We add one element per each filter to the Array ('all', 'error', etc.)
let logArrayProcessed = [];
for (let j = 0; j < LOG_FILTER.length; j++) {
logArrayProcessed[LOG_FILTER[j].id] = '';
}
// We apply regex here. This will also eliminate all log lines without proper info
// like date/time, log level, and entry.
let arrSplitLogLine = logLineSplit(strLogEntry);
if (arrSplitLogLine !== false) {
if (isLikeEmpty(LOG_FILTER) === false) {
// Now let's iterate over the filter array elements
// We check if both the "all" and "any" filters apply. If yes, - and blacklist false - we add the log line.
for (let k = 0; k < LOG_FILTER.length; k++) {
if ( (stringMatchesList(strLogEntry, LOG_FILTER[k].filter_all, true) === true)
&& (stringMatchesList(strLogEntry, LOG_FILTER[k].filter_any, false) === true)
&& (isBlacklisted(strLogEntry, LOG_FILTER[k].blacklist) === false) ) {
logArrayProcessed[LOG_FILTER[k].id] = logArrayProcessed[LOG_FILTER[k].id] + strLogEntry + "\n";
}
// Now we remove terms if desired per "clean" option
if (isLikeEmpty(LOG_FILTER[k].clean) === false) {
for (let lpTerm of LOG_FILTER[k].clean) {
if (! isLikeEmpty(lpTerm)) {
logArrayProcessed[LOG_FILTER[k].id] = logArrayProcessed[LOG_FILTER[k].id].replace(lpTerm, '');
}
}
}
}
}
}
return logArrayProcessed;
}
/*************************************************************************************************************************
* Further processing
*************************************************************************************************************************/
/**
* Further processes the log array and set states accordingly.
*
* @param {array} arrayLogInput The Array of the log input.
* Array is like:
* [
* ['info':'15.08.2019 09:27:55.476 info adapt.0 some log', 'error':''],
* ['info':'15.08.2019 09:33:58.522 info adapt.0 some more log', 'error':''],
* ['info':'', 'error':'15.08.2019 09:37:55.807 error adapt.0 some error log'],
* ]
* @param {boolean} [updateJsonOnly=false] Optional parameter. If true, then just the JSON states will be updated without
* considering arrayLogInput. Used for updated JSON every midnight due to texts
* "Today"/"Yesterday" in JSON table.
**/
function processLogArrayAndSetStates(arrayLogInput, updateJsonOnly) {
let justUpdateJson = (typeof updateJsonOnly == 'undefined') ? false : updateJsonOnly;
/*****************
* [1] Build array from LOG_FILTER. Looks like: arrayFilterIds = ['info', 'error', 'warn'].
* Also, build result array to keep our results. Lools like resultArr = [info: '', error: '', warn: '']
*****************/
let arrayFilterIds = [];
let resultArr = [];
for (let i = 0; i < LOG_FILTER.length; i++) {
arrayFilterIds.push(LOG_FILTER[i].id); // each LOG_FILTER id into array
resultArr[LOG_FILTER[i].id] = '';
}
if (! justUpdateJson) {
/*****************
* [2] Process element by element, so ['info':'log test', 'error':'log test'] of given array.
* We fill the result array accordingly.
*****************/
for (let lpElement of arrayLogInput) {
// Loop thru our new array arrayFilterIds and fill result array
for (let k = 0; k < arrayFilterIds.length; k++) {
// some variables
let lpFilterId = arrayFilterIds[k]; // Filter ID from LOG_FILTER, like 'error', 'info', 'custom', etc.
let lpNewLogLine = lpElement[lpFilterId]; // Current log line of provided array element of 'error', 'info', 'custom' etc.
if (isLikeEmpty(lpNewLogLine)) {
// No log content for the given filter id.
if (SCRIPT_DEBUG) log (DEBUG_IGNORE_STR + 'Filter [' + lpFilterId + ']: No match.');
} else {
if (SCRIPT_DEBUG) log (DEBUG_IGNORE_STR + 'Filter [' + lpFilterId + ']: Match! New Log Line length: (' + lpNewLogLine.length + ')');
// Append new log line to result array
if (isLikeEmpty(resultArr[lpFilterId])) {
resultArr[lpFilterId] = lpNewLogLine;
} else {
resultArr[lpFilterId] = lpNewLogLine + resultArr[lpFilterId]; // "\n" not needed, always added above
}
}
}
}
}
/*****************
* [3] We merge with the current state.
*****************/
for (let k = 0; k < arrayFilterIds.length; k++) {
let lpFilterId = arrayFilterIds[k]; // Filter ID from LOG_FILTER, like 'error', 'info', 'custom', etc.
let lpStatePath1stPart = FINAL_STATE_PATH + '.log' + cleanseStatePath(lpFilterId); // Get Path to state
let lpNewFinalLog = resultArr[lpFilterId];
if ( justUpdateJson || (! isLikeEmpty(lpNewFinalLog)) ) {
// Get state value
let strCurrentStateLog = getState(lpStatePath1stPart + '.log').val; // Get state contents of loop item
// Add state log lines to our final log
if ( !isLikeEmpty(strCurrentStateLog)) {
if (! justUpdateJson) {
lpNewFinalLog = lpNewFinalLog + strCurrentStateLog; // "\n" not needed, always added above
} else {
lpNewFinalLog = strCurrentStateLog;
}
}
// Convert to array for easier handling
let lpNewFinalLogArray = lpNewFinalLog.split(/\r?\n/);
// Remove duplicates
lpNewFinalLogArray = arrayRemoveDublicates(lpNewFinalLogArray);
// Remove empty values
lpNewFinalLogArray = cleanArray(lpNewFinalLogArray);
// Sort array descending
lpNewFinalLogArray = sortLogArrayByDate(lpNewFinalLogArray, 'desc');
// Merge Loglines if multiple values and add leading '[123 entries]' to log message
let doMerge = getConfigValuePerKey(LOG_FILTER, 'id', lpFilterId, 'merge');
if (doMerge || doMerge === 'true') { // also check for string 'true' in case user used string
lpNewFinalLogArray = mergeLogLines(lpNewFinalLogArray);
}
// We need a separate array for JSON
let lpNewFinalLogArrayJSON = lpNewFinalLogArray;
// Let's remove elements if time of when button '.clearJSON' was pressed is greater than log date.
lpNewFinalLogArrayJSON = clearJsonByDate(lpNewFinalLogArrayJSON, lpStatePath1stPart + '.clearJSON');
// Just keep the first x elements of the log. JSON log length is being set individually.
lpNewFinalLogArray = lpNewFinalLogArray.slice(0, MAX_LOG_LINES);
lpNewFinalLogArrayJSON = lpNewFinalLogArrayJSON.slice(0, getConfigValuePerKey(LOG_FILTER, 'id', lpFilterId, 'jsonMaxLines'));
// Get just the most recent log entry into string
let lpMostRecent = lpNewFinalLogArray[0];
// Sort ascending if desired
if (!getConfigValuePerKey(LOG_FILTER, 'id', lpFilterId, 'sortDescending')) {
lpNewFinalLogArray = lpNewFinalLogArray.reverse();
lpNewFinalLogArrayJSON = lpNewFinalLogArrayJSON.reverse();
}
// ** Finally set the states
///////////////////////////////
// -1- Full Log, String, separated by "\n"
///////////////////////////////
if (! justUpdateJson) {
let strFullLog = lpNewFinalLogArray.join("\n");
if (SCRIPT_DEBUG) log (DEBUG_IGNORE_STR + 'New length to be set into state: (' + strFullLog.length + '), state: [' + lpStatePath1stPart + '.log' + ']');
setState(lpStatePath1stPart + '.log', strFullLog);
}
///////////////////////////////
// -2- JSON, with elements date and msg
///////////////////////////////
// Let's put together the JSON
let jsonArr = [];
for (let j = 0; j < lpNewFinalLogArrayJSON.length; j++) {
// Get 4 elements in array: datetime, level, source, message
let arrSplitLogLine = logLineSplit(lpNewFinalLogArrayJSON[j]);
if (arrSplitLogLine !== false) {
let strLogMsg = arrSplitLogLine.message;
// Reduce the length for each log message per "jsonLogLength"
strLogMsg = strLogMsg.substr(0, LOG_FILTER[k].jsonLogLength);
// ++++++
// Build the final Array
// ++++++
// We need this section to generate the JSON with the columns (which ones, and order) as specified in LOG_FILTER
let objectJSONentry = {}; // object (https://stackoverflow.com/a/13488998)
if (isLikeEmpty(LOG_FILTER[k].jsonColumns)) log('Columns not specified in "jsonColumns".', 'warn');
// Prepare CSS
let strCSS1 = '', strCSS2 = '';
let strCSS1_level = '', strCSS2_level = '';
if (JSON_APPLY_CSS) {
strCSS1 = "<span class='log-" + arrSplitLogLine.level + "'>";
strCSS2 = '</span>';
strCSS1_level = strCSS1;
strCSS2_level = strCSS2;
if (LOG_FILTER[k].jsonCssToLevel) {
strCSS1 = '';
strCSS2 = '';
}
}
/**
* Support individual items in column provided through log
* Syntax: "Das ist ein Log ##{"msg":"Individuell", "source":"andere Quelle"}##"
*/
// Check if we actually have a hit
let individualRegexArr = strLogMsg.match(/##(\{\s?\".*\"\s?\})##/);
let individualRegexObjRes;
if (individualRegexArr != null) {
if(individualRegexArr[1] != undefined) {
individualRegexObjRes = JSON.parse(individualRegexArr[1]);
} else {
individualRegexObjRes = null;
}
} else {
individualRegexObjRes = null;
}
for (let lpCol of LOG_FILTER[k].jsonColumns) {
switch (lpCol) {
case 'date' :
let caseDate = formatLogDateStr(arrSplitLogLine.datetime, LOG_FILTER[k].jsonDateFormat);
if( (individualRegexObjRes != null) && (individualRegexObjRes['date'] != undefined) ) {
caseDate = individualRegexObjRes['date'];
}
objectJSONentry.date = strCSS1 + caseDate + strCSS2;
break;
case 'level' :
let caseLevel = arrSplitLogLine.level;
if( (individualRegexObjRes != null) && (individualRegexObjRes['level'] != undefined) ) {
caseLevel = individualRegexObjRes['level'];
}
objectJSONentry.level = strCSS1_level + caseLevel + strCSS2_level;
break;
case 'source' :
let caseSource = arrSplitLogLine.source;
if( (individualRegexObjRes != null) && (individualRegexObjRes['source'] != undefined) ) {
caseSource = individualRegexObjRes['source'];
}
objectJSONentry.source = strCSS1 + caseSource + strCSS2;
break;
case 'msg' :
let caseMsg = strLogMsg;
if( (individualRegexObjRes != null) && (individualRegexObjRes['msg'] != undefined) ) {
caseMsg = individualRegexObjRes['msg'];
}
objectJSONentry.msg = strCSS1 + caseMsg + strCSS2;
break;
default:
//nothing;
}
}
// Ok, so now we have the JSON entry.
jsonArr.push(objectJSONentry);
}
}
if (! isLikeEmpty(lpNewFinalLogArrayJSON)) {
setState(lpStatePath1stPart + '.logJSON', JSON.stringify(jsonArr));
setState(lpStatePath1stPart + '.logJSONcount', lpNewFinalLogArrayJSON.length);
}
}
}
/*****************
* [4] Finally done. Now we set states for the VIS views.
*****************/
if(FINAL_NUM_OF_VIS_VIEWS > 0) {
setTimeout(function() { // Apply timeout, to ensure all states are set.
for(let i = 0; i < FINAL_NUM_OF_VIS_VIEWS; i++) {
let lpStateViewSelFilter = FINAL_STATE_PATH + '.All.visView' + (i+1); // like: 0_userdata.0.Log-Script.All.visView1.whichFilter
let currentVisFilter = getState(lpStateViewSelFilter + '.whichFilter').val;
if(! isLikeEmpty(currentVisFilter)) {
let jsonStateToGet = LOG_STATE_PATH + '.log' + currentVisFilter + '.logJSON';
if( isState(jsonStateToGet) ) {
setState(lpStateViewSelFilter + '.outputJSON', getState(jsonStateToGet).val); // Finally: set state
setState(lpStateViewSelFilter + '.outputJSONcount', getState(jsonStateToGet + 'count').val); // Finally: set state
} else {
log('Log-Script-Fehler: Gewählter Filter ' + currentVisFilter + ', aber Datenpunkt [' + jsonStateToGet + '] ist nicht vorhanden.', 'error');
}
}
}
}, 2000);
}
}
/*************************************************************************************************************************
* Script specific supporting functions
*************************************************************************************************************************/
/**
* Subscribe to all Log-Script.logXXXX.clearJSON
* This will allow to clear JSON log if button is pressed.
*/
function subscribeClearJson() {
// Set current date to state if button is pressed
let logSubscribe = '';
for (let i = 0; i < LOG_FILTER.length; i++) {
let lpFilterId = cleanseStatePath(LOG_FILTER[i].id);
let lpStateFirstPart = FINAL_STATE_PATH + '.log' + lpFilterId;
logSubscribe += ( (logSubscribe === '') ? '' : ', ') + lpFilterId;
on({id: lpStateFirstPart + '.clearJSON', change: 'any', val: true}, function(obj) {
let stateBtnPth = obj.id // e.g. [javascript.0.Log-Script.logInfo.clearJSON]
let firstPart = stateBtnPth.substring(0, stateBtnPth.length-10); // get first part of obj.id, like "javascript.0.Log-Script.logInfo"
let filterID = firstPart.slice(firstPart.lastIndexOf('.') + 1); // gets the filter id, like "logInfo"
if (SCRIPT_DEBUG) log(DEBUG_IGNORE_STR + 'Clear JSON states for [' + filterID + '].');
// We clear the according JSON states
setState(firstPart + '.logJSON', '[]');
setState(firstPart + '.logJSONcount', 0);
});
}
if (SCRIPT_DEBUG) log (DEBUG_IGNORE_STR + 'Subscribing to Clear JSON Buttons: ' + logSubscribe)
}
/**
* Subscribe to all .All.clearAllJSON
*/
function stateSubscribeClearAllJSON() {
on({id: FINAL_STATE_PATH + '.All.clearAllJSON', change: 'any', val: true}, function (obj) {
// 1. All fitered log states
const ALL_FILTER_IDS = getAllFilterIds();
for (let loopFilterId of ALL_FILTER_IDS) {
// Version 4.5.6
// See https://forum.iobroker.net/post/375932
// We do no longer set the target states directly, but use the according clearJSON instead.
// This is to ensure that user can use the clearJSON timestamp for the time of last clearJSON.
setState(FINAL_STATE_PATH + '.log' + loopFilterId + '.clearJSON', true);
// setState(FINAL_STATE_PATH + '.log' + loopFilterId + '.logJSON', '[]');
// setState(FINAL_STATE_PATH + '.log' + loopFilterId + '.logJSONcount', 0);
}
// 2. Vis add-ons
if(FINAL_NUM_OF_VIS_VIEWS > 0) {