Use FortiSIEM’s REST event query API. Post an XML query to /phoenix/rest/query/eventQuery, which returns a query ID, poll the progress until it reaches 100, then fetch the events. The results come back as XML. The original log line of each event is in the rawEventMsg attribute, so a few lines of Python turn the result into raw logs. Exports from the Analytics screen come out in formats LogTotal doesn’t read today.
FortiSIEM is common wherever Fortinet runs the network, and it often holds far more than firewall logs. Prime Core has 19,692 detection rules for FortiSIEM, mapped to 664 MITRE ATT&CK techniques. Below is how to get events out, sanitize them, and investigate them for free in LogTotal.
Before you start
An API user. Use an account with rights to run analytics queries. The API authenticates with basic auth, with the organization in the username: super/<user> on an enterprise install, <org>/<user> for a specific organization in a service provider install.
Retention. Online event storage is limited. Older events may sit in archive storage that needs extra steps.
Attribute names. FortiSIEM queries use its own attribute names, such as reptDevName (reporting device), reptDevIpAddr, eventType and phRecvTime. Build the filter in Analytics first.
Export with the event query API
Save the query as query.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Reports><Report><Name>LogTotal export</Name><Description/>
<SelectClause><AttrList>phRecvTime,reptDevIpAddr,eventType,rawEventMsg</AttrList></SelectClause>
<ReportInterval><Low>1792368000</Low><High>1792454400</High></ReportInterval>
<PatternClause><SubPattern id="1" name="Filter">
<SingleEvtConstr>reptDevName = "web-03"</SingleEvtConstr>
</SubPattern></PatternClause>
</Report></Reports>
The interval is epoch seconds for 2026-10-19 00:00 UTC to 2026-10-20 00:00 UTC. Then run it:
FSM="https://fortisiem.example.com"
AUTH="super/apiuser:$FSM_PASS"
QID=$(curl -sS -u "$AUTH" -X POST -H 'Content-Type: text/xml' --data @query.xml "$FSM/phoenix/rest/query/eventQuery")
until [ "$(curl -sS -u "$AUTH" "$FSM/phoenix/rest/query/progress/$QID")" = "100" ]; do sleep 5; done
curl -sS -u "$AUTH" "$FSM/phoenix/rest/query/events/$QID/0/1000" > fsm_web03_1019.xml
The last two path segments are the start offset and the count. Page through large results in steps of 1,000. Then pull out the raw messages:
import xml.etree.ElementTree as ET
import xml.etree.ElementTree as ET
root = ET.parse("fsm_web03_1019.xml").getroot()
with open("fsm_web03_1019.log", "w") as out:
for attr in root.iter("attribute"):
if attr.get("name") == "rawEventMsg" and attr.text:
out.write(attr.text.strip() + "\n")
Upload, sanitize and review in LogTotal
- Upload. Open logtotal.com and drop in the file.
- Sanitize.
- Review.
What this looks like on real data.
When it goes wrong
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 | Organization missing from the username | Use super/<user> or <org>/<user> |
| Query returns an error instead of an ID | XML syntax or an unknown attribute name | Test the filter in Analytics; check attribute names |
| Progress never reaches 100 | Query too broad | Narrow the time range and filter |
| rawEventMsg empty | The attribute wasn’t selected | Add rawEventMsg to AttrList |
| Old events missing | They’re in archive storage | Check archive options |
FAQ
Why XML?
That’s what this FortiSIEM API speaks. The Python step converts it to the original raw lines, which is usually what you want to upload anyway.
Can I export incidents instead?
Incidents have their own API calls. For LogTotal, export the events behind them.