Two conversations decide what you spend on engineering licenses, and you rarely walk into either with the evidence you need. The first is the annual renewal, where the vendor’s rep has a quote, a list price, and a number to hit — and you have a hunch about whether you even use what you already pay for. The second is the audit or true-up, where the vendor asserts what you owe and the burden of disproving it lands on you. Both come down to the same question: can you prove what your organization actually used?
Here’s the part that’s easy to miss: for the teams LiMon is built for — floating license servers running on your own network, no phone-home — the vendor doesn’t have that answer either. Your FlexLM, RLM, LM-X, and DSLS servers don’t report usage to anyone. That cuts both ways: it’s why the vendor leans on list prices, seat counts, and audit rights instead of your real numbers, and it’s why, if you haven’t kept your own record, there’s no number in the room but theirs.
So the job is to keep that record. LiMon does part of it just by watching your license servers from the network: it polls them continuously and stores what it sees, so a usage history accumulates from the day you deploy it. But polling has blind spots it can’t close on its own — the sessions too short to fall between two polls, and above all the denials, which a scheduled poll catches only in glimpses, if the vendor surfaces them live at all. The log files those servers already write fill those gaps, and they reach back to before LiMon was watching. Importing them — from the command line, the web UI, or the REST API — is how you complete the record. The harder part, and most of this article, is making sure what you import is trustworthy enough to put in front of a vendor.
Doesn’t real-time monitoring make log import redundant?
It’s a fair question. Server logs contain the checkouts, checkins, and usually a bit more, depending on the vendor. So at first glance you might assume that a scheduled log ingestion duplicates what network polling already does — and that you could pick one or the other. Not really.
Network polling gives you the now — who has what checked out at this moment, whether the daemon is healthy, whether the pool is at 100% — and, because LiMon stores every poll, a running history from the moment you deploy it. That live view is what tells you something is on fire before the tickets arrive, and a nightly log ingestion can’t do it: by the time it sees an event, the user has come and gone. What the logs add is reach — into what happened between polls, into denials a live poll can’t reconstruct in full, and into the months before you started watching.
Those logs should be a clean record of that history. They’re not, anymore, and that’s deliberate. Most vendors today are explicit in the file headers that the contents are “for debugging only” and not suitable for usage analysis. Out-of-order checkin/checkout events, missing timestamps, license file rereads that log duplicate checkouts, client reconnections that generate entries no real user produced — the list is long and the intent is clear. Vendors would prefer you bought their proprietary analytics suite, or engaged their professional services, rather than mine the free logs they already produce.
Their customers are the software publishers that license through them, not you. They are not in the business of helping you buy less from their customers — and they are certainly not in the business of building the case you’d use against them at renewal.
So the value of importing the logs isn’t that they’re perfect. It’s that, treated carefully, they fill three gaps that polling alone leaves open.
What polling misses, and logs catch
Short sessions. Polling is scheduled. If a checkout starts and ends between two polls, LiMon never sees it. For an editor like NX that engineers leave open for hours, missing the occasional session is a rounding error. For ABAQUS jobs that finish a FEA solve in under a minute, polling can make a feature look idle when in reality your team is hitting it frequently. The log file has the full trace — and the gap cuts against you: write a busy feature off as idle, drop its seats to save money, and you’ll spend the next quarter fielding the denials.
Denials. Polling will tell you the pool is at 100%. The log will tell you who tried to check out a license and got turned away. That’s the difference between “we’re using everything we own” and “we don’t own enough” — and it’s the single most valuable thing the logs give you. It gets its own section below.
Server-side events the network view doesn’t expose. Vendors keep some genuinely useful information in the logs that the protocol itself doesn’t reveal. A server that’s failing to serve some of its own licenses. Clients hitting it with the wrong version. Requests for features you don’t have licensed. Most of these are silent until you go looking, and you only find them in the logs.
Denials: proof, not just pressure
A denial is the event where a user requested a license and the server had none to give. FlexLM writes it as DENIED, RLM as DENY, LM-X and DSLS in their own denial records. Each one names the user, the feature, and the moment — and that specificity is exactly what a renewal argument usually lacks.
Here’s how the conversation normally goes without it. Users complain to you. The vendor’s rep — whose answer to any capacity question is “buy more seats” — is glad to help you do exactly that. Polling alone gives you utilization, a strong signal that you’re running hot but not a verdict. What you can’t do is put a number on the shortfall, so the negotiation runs on anecdote and the rep’s framing wins.
Denial data changes that in both directions, which is the point — it’s evidence, not ammunition:
- Sometimes it confirms the upsell. Two hundred denials a month on a single feature, spread across the whole engineering team, is a genuine capacity problem. Now you’re asking for a specific number of seats backed by a specific count, not pleading.
- Just as often it kills it. Pull the same data and you find the denials clustered on three users launching overnight batch runs that collide for ten minutes at 2 a.m. That’s a scheduling fix, not a purchase — and you’ve just saved yourself an upsell you’d have approved on vibes.
Denial counts also let you quantify the cost of saying no: engineer-hours lost waiting on a license, jobs that didn’t run. That’s the number finance wants sitting next to “cost of more seats,” and it’s the one you can only produce from the logs.
Two cautions, because a denial count you can’t defend is worse than none. First, one frustrated user retrying a checkout five times in a minute is five DENIED lines but one real denial — count events naively and you’ll overstate the problem and lose credibility the moment the vendor asks. Second, some vendors only write denials to a separate stream you have to switch on (see LM-X below); if it was never enabled, the absence of denials in the log is not evidence there were none.
Audit defense: your numbers before their invoice
A software audit — or its politer cousin, the true-up — starts with the vendor telling you what they believe you deployed and used, and asking you to reconcile. The asymmetry is the whole problem: they arrive with a position, built from your entitlement counts, list prices, deployment records, and whatever you’ve been contractually obliged to self-report — and you’re reacting to it. They can’t see your on-prem servers, but that doesn’t help you if the only usage figures on the table are the ones they inferred. The only thing that levels it is having independently kept your own continuous record of what your servers actually served.
That record is what a clean log import builds. Concretely, audit-defense evidence is:
- Continuous, not sampled. An audit can look back twelve months or more. A dashboard that only holds the last 90 days of detail can’t answer for a period you no longer have data on. The evidence has to be retained for at least your full contract term, which means the import has to have been running before you needed it — you cannot reconstruct a quarter whose logs were rotated away.
- Reconciled, not raw. Handing a vendor a pile of debug logs invites them to interpret the messy parts in their favor — and hands over your usernames and workstation names with it, which is worth scrubbing first. What holds up is a normalized, deduplicated usage history where the LINGER sessions, rereads, and reconnect artifacts (below) have already been accounted for — a number you can explain line by line.
- Peak-aware. Concurrent-use licensing is priced on your peak simultaneous usage, not your average. Your defense stands or falls on an accurate peak, and an accurate peak depends on getting the checkin events right (skip them and every session looks infinite — see the failure modes).
Be honest with yourself about what this does and doesn’t do. Your logs are your record; they won’t always match the vendor’s to the token, and they are not a legal shield. What they buy you is the ability to walk into the conversation with a defensible number of your own instead of accepting theirs — which is usually the difference between negotiating and signing.
What each format actually contains
The supported log formats look similar from a distance — timestamps, usernames, feature names — but each has its own gaps, and each captures denials a little differently.
FlexLM debug log (lmgrd -l <path>)
The richest of the bunch. Records OUT, IN, DENIED, QUEUED, vendor daemon health, lmgrd restarts, and license file rereads. Caveats:
- The default rotation behavior truncates the file on restart. Always start
lmgrdwith-l +pathso the log appends instead of overwriting — a truncated log is a gap in your audit trail. - Borrowed checkouts (
LINGER) appear as long sessions even after the user has disconnected. Without filtering, you’ll over-count concurrency — and an inflated peak is a number you can’t defend. - Some vendor daemons emit non-ASCII characters in usernames or hostnames in the system locale, which is rarely what a naive parser expects.
RLM report log (REPORTLOG +<path>)
Designed for accounting rather than debugging. Cleaner format than FlexLM, with explicit START/PRODUCT/OUT/IN/DENY/STOP records — which makes it the most audit-friendly of the four out of the box. Caveats:
- The
+prefix on the path is mandatory for append mode. Without it, every RLM restart wipes the file. - Report logs don’t include queue events. If you care about queueing pressure, you also need the standard
rlm.log. - Roaming checkouts can extend past the actual user session by hours.
LM-X usage log
LM-X writes structured per-checkout records by default, which makes parsing relatively straightforward. Caveats:
- LM-X separates “license usage” from “license denials.” You may need to enable both with
LICENSE_LOG=1and make sure the denial log is captured — if it was off, your denial history for that period simply doesn’t exist. - Per-server logs need consolidation if you run a redundant pool; LM-X does not auto-merge.
DSLS usage history
DSLS (the Dassault Systèmes license server) keeps usage in its own database that you export with DSLicSrv -admin. Caveats:
- DSLS rotates its history on its own schedule; if you don’t export at least daily, you lose granularity you can’t get back.
- Token-based products (CATIA, 3DEXPERIENCE) report token consumption, not seats. The token-to-seat mapping varies by product and release — get it wrong and your audit numbers are wrong in the vendor’s favor.
The quiet failure modes
Most bad imports don’t fail loudly. They produce numbers that look reasonable and are slightly wrong — which is the worst outcome when you’re going to stake a renewal or an audit response on them. These are the patterns to watch for whether you’re rolling your own pipeline or evaluating someone else’s.
Rotation without overlap. Logs rotate at midnight, the import job runs at 1 a.m., and anything written in between disappears. The fix is to keep the previous rotation’s file readable for at least 48 hours and to track import position by byte offset or content hash, not by file timestamp.
Timezone drift. License servers run in whatever timezone the OS happens to use — sometimes UTC, sometimes local, occasionally local without DST awareness. Every twice-yearly DST change becomes either a one-hour gap or a one-hour duplicate. Verify what the server actually emits before normalizing.
Encoding and locale. Active Directory usernames often carry accented characters. FlexLM and RLM emit them in the system locale (CP1252 on Windows, UTF-8 on most modern Linux). Müller becomes M?ller if your importer assumes UTF-8 everywhere, and your per-user reports stop matching reality.
Truncated lines under load. When the license server is busy and the log directory sits on slow storage (NFS is a frequent culprit), individual lines can be truncated mid-write. A robust parser flags those as parse errors rather than silently interpreting a partial line as something it isn’t.
Skipping IN events. Filter only on OUT and DENIED and every checkout looks like it lasted forever. This is the single most common reason concurrency reports show absurd peak numbers — and since concurrent licensing is priced on the peak, it’s also the fastest way to argue yourself into buying seats you don’t need. Always import the full event lifecycle, even if your reports only look at start times.
Polling and logs working together
The hard part isn’t parsing the logs. It’s combining them with what polling already saw, without double-counting and without leaving gaps.
LiMon handles that reconciliation in the background. Imports can be triggered on demand or on a schedule, from the command line or through the web interface, and either path coordinates with the other — a nightly automated import isn’t going to step on an operator’s ad-hoc upload for the same server. Once the raw events are in, LiMon rebuilds the affected date range, merging the fresh log evidence with the sessions it already had from polling, so the dashboards and reports for those dates reflect the combined picture instead of two versions of the truth.
That combined record is what feeds the rest of the product: the cost-optimization views that track utilization and contention over time, and the executive reports for renewal negotiations and audit responses. The reports are ultimately what justifies the careful import work — a renewal conversation goes very differently when you can hand the vendor a clean twelve-month breakdown, denials included, than when you can only describe what you remember.
A short audit-readiness checklist
If you’re reviewing your own setup today, regardless of tool:
- Verify whether your license servers are running with append-mode logging (
lmgrd -l +path,REPORTLOG +path) — and, for LM-X, that denial logging is actually switched on. - Confirm the timezone the servers actually emit in their log files.
- Make sure your importer tracks position by byte offset, not by file timestamp, and that you retain history for at least your full contract term.
- Spot-check a few lines with non-ASCII characters and confirm they round-trip through your store correctly.
- Pick one feature and reconcile its count of
OUTevents againstINevents — they should be close. Small drift from open-at-shutdown sessions is normal. - Pull a denial count for one busy feature and sanity-check it against reality — are these distinct shortfalls, or one user retrying?
If any of those return surprises, the rest of your numbers are at risk too — which means so is the case you’d make with them.
Where LiMon fits
Most teams running engineering licenses have better things to do than maintain their own parsing pipeline. LiMon does the polling, the log ingestion, and the reconciliation in a single on-premises stack — no agents on the license servers, no cloud, no phone-home. Request an evaluation to try the workflow, then pick the platform tier for your server scale. Active maintenance unlocks the Intelligence views on top — Audit Defense and Savings among them — interactive dashboards you explore live and export when a vendor or your CFO needs a document. That’s the difference between “we monitored everything” and “we can prove it on the renewal call.”