Skip to content

Commit 07f8dc4

Browse files
authored
Merge pull request #101 from sy-c/master
v2.10.0
2 parents 826f88d + ccdfbaa commit 07f8dc4

4 files changed

Lines changed: 695 additions & 2 deletions

File tree

doc/releaseNotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,7 @@ This file describes the main feature changes for each InfoLogger released versio
182182
- o2-infologger-alert service
183183
- o2-infologger-browser:
184184
- added some extra startup option, to preconfigure filters
185+
186+
# v2.10.0 - 26/1/2026
187+
- o2-infologger-httpd: inject log messages from HTTP request
188+
- o2-infologger-status: creates periodically a HTML report of recent messages received by infoLoggerServer

src/InfoLoggerDispatchStats.cxx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "ConfigInfoLoggerServer.h"
3030
#include "infoLoggerMessage.h"
3131

32+
#define INDEX_SEPARATOR "_"
33+
3234
using namespace std::chrono;
3335

3436
////////////////////////////////////////////////////////
@@ -90,7 +92,7 @@ InfoLoggerDispatchStats::InfoLoggerDispatchStats(ConfigInfoLoggerServer* config,
9092
return; // invalid index name
9193
}
9294
lix.push_back(i);
93-
if (lix.size()>1) nix += "-";
95+
if (lix.size()>1) nix += INDEX_SEPARATOR;
9496
nix += name;
9597
}
9698
dPtr->ilgFieldsToIndex.push_back(std::pair(std::move(nix), std::move(lix)));
@@ -234,7 +236,7 @@ int InfoLoggerDispatchStats::customMessageProcess(std::shared_ptr<InfoLoggerMess
234236
for (int ii = 0 ; ii < (int)dPtr->ilgFieldsToIndex[id].second.size(); ii++) {
235237
if (debug) {printf(" get [%d]\n", dPtr->ilgFieldsToIndex[id].second[ii]);}
236238
if (ii) {
237-
v += "-";
239+
v += INDEX_SEPARATOR;
238240
}
239241
std::string fv = getStringValue(lmsg, dPtr->ilgFieldsToIndex[id].second[ii]);
240242
if (debug) {printf(" = %s\n",fv.c_str());}
@@ -434,7 +436,14 @@ int InfoLoggerDispatchStats::customLoop()
434436
};
435437

436438
std::string txt;
439+
bool isFirst = 1;
437440
for (const auto& [timestamp, window] : dPtr->windows) {
441+
if (isFirst) {
442+
isFirst = 0;
443+
} else {
444+
txt += " ";
445+
}
446+
438447
//txt += "{ " + std::to_string(timestamp) + " " + toTclList(window) + " }";
439448
txt += toTclList(window);
440449
}

src/o2-infologger-httpd

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#!/usr/bin/tclsh
2+
3+
# daemon to inject log messages from HTTP requests
4+
# example request: http://ali-staging:8084/log?Message=This+is+a+test+error&Facility=test&Severity=E
5+
#
6+
# open port: firewall-cmd --zone=public --permanent --add-port=8084/tcp; firewall-cmd --reload
7+
# start daemon manually: [root@alio2-cr1-hv-mvs00 ~]# nohup /root/o2-infologger-httpd > /tmp/o2-infologger-httpd.log 2>&1 &
8+
9+
# v1.0 03/07/2025 - initial release
10+
11+
set cfg(RunWithoutDeps) 0
12+
set cfg(Debug) 0
13+
set cfg(HTTPPort) 8084
14+
15+
set infoLoggerFields {Facility Role System Detector Partition Run Severity Level ErrorCode SourceFile SourceLine}
16+
17+
18+
####################
19+
20+
21+
# function to log on stdout
22+
proc doLog {msg} {
23+
set t [clock format [clock seconds] -format "%d/%m/%Y %H:%M:%S"]
24+
puts "$t\t$msg"
25+
}
26+
27+
28+
# function to log on stdout
29+
proc doLogDebug {msg} {
30+
global cfg
31+
if {!$cfg(Debug)} {return}
32+
set t [clock format [clock seconds] -format "%d/%m/%Y %H:%M:%S"]
33+
#puts "$t\t$msg"
34+
puts "$msg"
35+
}
36+
37+
38+
# function to log on InfoLogger
39+
proc doLogIlg {errcode msg} {
40+
global logHandle
41+
global logContext
42+
if {$logHandle == ""} {
43+
return
44+
}
45+
46+
$logContext setField "ErrorCode" "$errcode"
47+
$logHandle log $logContext "$msg"
48+
doLog "$msg"
49+
logResetFields
50+
}
51+
52+
53+
####################
54+
# check dependencies
55+
####################
56+
57+
set dependenciesOk 1
58+
59+
# try to load infoLogger library
60+
set defaultLevel 11
61+
set defaultSeverity "I"
62+
proc logResetFields {} {
63+
global logHandle
64+
global logContext
65+
global defaultLevel
66+
global defaultSeverity
67+
$logContext setField "Facility" "ilg/httpd"
68+
$logContext setField "System" "FLP"
69+
$logContext setField "Level" "$defaultLevel"
70+
$logContext setField "Severity" "$defaultSeverity"
71+
$logContext setField "ErrorCode" ""
72+
}
73+
74+
if {[catch {
75+
set logHandle ""
76+
load /opt/o2-InfoLogger/lib/infoLoggerForTcl.so
77+
set logHandle [InfoLogger]
78+
set logContext [InfoLoggerMetadata]
79+
logResetFields
80+
} err]} {
81+
doLog "Failed to init infoLogger library: $err"
82+
set dependenciesOk 0
83+
}
84+
85+
# exit or continue
86+
if {(!$dependenciesOk)} {
87+
if ($cfg(RunWithoutDeps)) {
88+
doLog "Dependencies failed, but continue running"
89+
} else {
90+
doLog "Dependencies failed, exiting"
91+
exit 1
92+
}
93+
}
94+
95+
########################
96+
# end check dependencies
97+
########################
98+
99+
100+
doLog "Starting infoLogger HTTPD bridge - pid [pid]"
101+
102+
103+
# Procedure to handle incoming connections
104+
proc handle_connection {sock addr port} {
105+
doLogDebug "Connection from $addr:$port"
106+
fconfigure $sock -blocking 0 -buffering line
107+
fileevent $sock readable [list read_request $sock]
108+
}
109+
110+
# URL decode helper (converts %XX to character, + to space)
111+
proc urldecode {str} {
112+
set str [string map {+ " "} $str]
113+
set result ""
114+
set i 0
115+
while {$i < [string length $str]} {
116+
if {[string index $str $i] eq "%"} {
117+
set hex [string range $str [expr {$i+1}] [expr {$i+2}]]
118+
append result [binary format c [scan $hex %x]]
119+
incr i 3
120+
} else {
121+
append result [string index $str $i]
122+
incr i
123+
}
124+
}
125+
return $result
126+
}
127+
128+
# Parse query parameters into a dict
129+
proc parse_query {query} {
130+
set params {}
131+
foreach pair [split $query "&"] {
132+
if {[regexp {([^=]+)=?(.*)} $pair -> key value]} {
133+
set key [urldecode $key]
134+
set value [urldecode $value]
135+
dict set params $key $value
136+
}
137+
}
138+
return $params
139+
}
140+
141+
# Request handling
142+
proc read_request {sock} {
143+
if {[eof $sock]} {
144+
close $sock
145+
return
146+
}
147+
148+
gets $sock line
149+
doLogDebug "Received: $line"
150+
151+
# First line: GET /path?key=value HTTP/1.1
152+
if {[regexp {^GET\s+([^?\s]+)\??([^ ]*)\s+HTTP/} $line -> path query]} {
153+
doLogDebug "Requested path: $path"
154+
if {$query ne ""} {
155+
doLogDebug "Query string: $query"
156+
set params [parse_query $query]
157+
doLogDebug "Parsed parameters:"
158+
foreach {key value} $params {
159+
doLogDebug " $key = $value"
160+
}
161+
processQuery $path $params
162+
}
163+
}
164+
165+
# End of headers: empty line
166+
if {[string trim $line] eq ""} {
167+
# Send empty HTTP response
168+
puts $sock "HTTP/1.1 200 OK\r"
169+
puts $sock "Content-Length: 0\r"
170+
puts $sock "Connection: close\r"
171+
puts $sock "\r"
172+
flush $sock
173+
close $sock
174+
}
175+
}
176+
177+
178+
# process queries
179+
proc processQuery {path params} {
180+
# path is the path from HTTP request
181+
# params is a dict with key/value pairs
182+
if {$path == "/log"} {
183+
global logHandle
184+
if {$logHandle == ""} { return }
185+
186+
if {[dict exists $params Message]} {
187+
set msg [dict get $params Message]
188+
189+
set logContext [InfoLoggerMetadata]
190+
global infoLoggerFields
191+
foreach key $infoLoggerFields {
192+
if {[dict exists $params $key]} {
193+
set value [dict get $params $key]
194+
$logContext setField $key $value
195+
doLog "$key = $value"
196+
}
197+
}
198+
$logHandle log $logContext "$msg"
199+
doLog "LOG: $msg"
200+
}
201+
}
202+
}
203+
204+
205+
206+
# Start listening
207+
socket -server handle_connection $cfg(HTTPPort)
208+
doLog "Listening on port $cfg(HTTPPort)..."
209+
vwait forever

0 commit comments

Comments
 (0)