← Blog

Filament, cost, and which revision worked

Where a print record should live, which numbers are measured and which estimated, and how to read filament use and cost per model, revision, and printer.

guidecost-trackingfilamentworkflow

Track filament use and cost by recording every finished job against the file that produced it, then reading the measured numbers back out of that record. Moonraker already logs duration and filament used for each job, and Mainsail or Fluidd will show you the list. The part it cannot tell you is which slice of which part ran, so at the end of a month you know how much filament went through the machine but not which version of the bracket printed clean or what a batch of them cost.

Closing that gap is mostly a question of what the job is filed under.

What a useful print record holds

A job entry earns its keep when it can answer a question weeks later. That takes a handful of fields:

  • the file that printed, and which revision of which model that file is;
  • the machine it ran on;
  • the outcome, kept separate for completed, cancelled, and failed;
  • elapsed duration, marked as measured or estimated;
  • filament used, again marked as measured or estimated;
  • the spool, so cost uses a real price rather than a generic material rate;
  • the cost as it stood when the print finished.

The last one matters more than it looks. Filament prices change, and a history that recalculates old prints against today’s price per kilogram is not a record of what you spent.

What Moonraker and OctoPrint already give you

Moonraker’s history component is loaded whether or not moonraker.conf mentions it, since it sits in the server’s core component list. /server/history/list returns per-job filename, status, start_time, end_time, print_duration, total_duration, filament_used, and the file metadata as it stood at the time of the job.

Mainsail turns that into a History page: total print time, longest print, average time per job, total filament, job count, a completed/cancelled/failed breakdown, filament and print-time charts, and a job list filterable by status and searchable by filename. Fluidd shows a similar view. For one printer with disciplined filenames, this is enough, and running a second service to duplicate it would be silly.

The limit is what the data is keyed on. Every entry is a filename on one machine. Export a second variant under a new name and nothing connects the two, because there is no model both files belong to. Move the same file to a second printer and you get two unrelated histories.

OctoPrint records less on its own: per-file counters in the file list, covering success and failure counts and the last print’s date, duration, and result. Fuller records come from plugins. Print History and PrintJobHistory each keep a job database with times, status, and filament, and PrintJobHistory pulls thumbnails and filament figures from other plugins when they are installed. Both are maintained separately from OctoPrint, and PrintJobHistory spent a period abandoned before new maintainers picked it up for bug fixes, which is worth knowing before a workshop’s cost records depend on it.

Attaching the job to the model

PrintStash records a job against the G-code revision it came from, so the history lives on the part rather than on the machine. Each model’s History tab lists its jobs with the revision number, the printer, the material, and when it ran. Where measured data came back, the row carries a measured line with the duration, the grams, and the cost, plus the spool name if one was selected. Failed jobs keep the error text the printer reported.

There are three ways a job gets there.

Sending a revision to a connected printer from the library creates the job up front, and the status feed fills in progress and the terminal state as the print runs. This is the path that gets you everything, because PrintStash knows which revision it sent.

Logging by hand covers the rest. The Add record panel takes a registered printer or a free-text name for one that is not in PrintStash at all, then the revision, the state, start and finish times, and a spool. Resin printers, a friend’s machine, a run you did off an SD card: they all land in the same history as long as the revision is in the library.

Importing pulls a Moonraker printer’s own history onto a model. It reads the printer’s last hundred history entries, matches them case-insensitively against that model’s G-code filenames, and records the new matches. Anything already recorded for that printer and model is skipped, so re-running it never piles up duplicates. The dedup key is the filename, though, which means a file you have printed six times imports once. Use it to backfill what happened before you set any of this up, not as a running sync.

There is a fourth case worth naming because it half works. A print started from Mainsail or Fluidd on a connected Moonraker printer is captured, with its duration and measured filament, but PrintStash has no live job waiting and matches on remote filename alone, so the record lands on an internal placeholder rather than on your model. The revision you were testing gets no outcome from it. Sending from the library and then watching in Fluidd is the way to have both.

Where the cost number comes from

Cost is resolved once, at the moment a job is marked completed, and frozen from then on. Editing a filament profile’s price afterwards does not revise it.

The grams come from the measurement when there is one and from the slicer’s estimated weight in the file’s metadata when there is not. The price per kilogram comes from the filament profile linked to the selected spool when a Spoolman spool was chosen, which gives the spool’s real price and its own density and diameter, and otherwise from a local profile matched on brand and material.

Measured grams are Moonraker only. It is the sole provider declaring the measured-consumption capability, and the others record the slicer estimate instead. Measured elapsed duration is a separate thing and does come back from PrusaLink, OctoPrint, and Elegoo Centauri as well, though only Moonraker’s has been checked against real prints. Bambu LAN reports neither. The compatibility matrix has the per-provider grid.

That difference is the reason to compare within a provider rather than across two. An estimate and a measurement diverge for ordinary reasons: purge lines, a partial failure, a spool swap mid-print, a profile that has drifted from reality. Neither number is wrong. They answer different questions.

Connecting Spoolman is what makes the price exact rather than approximate, and it decrements the spool by the measured grams once the job commits, with a check that skips the write when Moonraker’s own Spoolman hook is already doing it.

Reading the history back

For the whole library, the Statistics page (admin only) aggregates completed jobs over 7, 30, or 90 days, a year, or all time: total cost, print count, filament used, average filament per print, total print time, and a 7-day filament forecast extrapolated from the period’s daily average. A cost, filament, or prints series plots over time as an area, line, or bar chart, and four rankings cover most printed models, printer workload, filament usage, and top collections. Cost appears in the display currency set under Settings -> Design.

Two caveats on those totals. Only completed jobs are counted, so the filament and money burned on failures is not in them. And print time falls back to the slicer estimate for jobs with no measured duration, which is most jobs on a non-Moonraker machine.

Back on the model grid, the browse filters include Printed as a yes or no and Print outcome by state, and the sorts include recently printed and best success rate. Both go into the URL and can be kept as a saved view, so “PETG parts that have failed at least once” becomes a bookmark instead of a search you rebuild each time. A model’s success rate counts completed against completed plus failed; cancellations stay out of the denominator, since cancelling a print usually says something about you rather than about the file.

The comparison view is what pays for the whole arrangement. Select two revisions and their parsed slicer settings appear side by side, with the outcomes underneath: prints, completed, failed, success rate, average actual time, actual filament, and actual cost for each. A filename-keyed history cannot produce that table, and it is the one that tells you whether the extra wall was worth six more minutes and four more grams. The revision tracking guide covers the labelling habits that make it readable.

What it does not do

The history is a record of filament and machine time. It has nothing to say about electricity, labor, machine wear, or the overhead of the prints that failed, and those are usually a larger share of a quote than the plastic. What a 3D print actually costs works through the rates you still have to supply yourself.

Print jobs are also not in the metadata export. The CSV and JSON exports are one row per stored file and carry model, collection, tag, revision, and slicer fields. The portable library archive does carry print history, with each job’s state, printer name, measured filament, duration, cost, and timestamps, so history survives a move to another installation but is not the thing to reach for when you want a spreadsheet of last quarter’s jobs.

A reasonable starting point

If you run Moonraker and one printer, read Mainsail’s History page and stop there until filenames stop being a usable index. That usually happens when the same part accumulates a few slices, or when a second machine turns up and the two histories no longer add up to anything.

At that point the useful move is small: put the source model in a library, add each slice to it as a revision, import the printer’s existing history onto the models it matches, and send prints from the library from then on. The record starts accumulating against parts instead of filenames, and the compare view has something to show within a few prints.

Questions that come up

Can I log a print from a printer PrintStash cannot reach?

Yes. The Add record panel takes a free-text printer name instead of a registered printer, so a machine with no supported provider, or one PrintStash has no route to, still gets its jobs filed against the right revision. You supply the state, the start and finish times, and optionally the spool. Cost comes from the slicer’s estimated weight in the file’s metadata, since nothing measured the print. Those records sort and filter alongside the automatic ones and count toward the model’s success rate, which makes manual entry the practical route for a resin printer or anything else outside the provider list.

Why does an old print keep its old cost after I change the filament price?

Because the cost is resolved once, at the moment the job is marked completed, and stored on the job row. A record that recalculated itself against the current price per kilogram would tell you what the print would cost today, which is a different and much less useful fact than what it cost. The same freezing applies to the grams: the effective weight used for the cost is stored next to it. If you need the current-price figure, take the stored grams and multiply.

Can I backfill the history that is already on my printer?

For Moonraker, yes, one model at a time. The import fetches the printer’s recent history and records the entries whose filenames match that model’s G-code files, bringing over the status, timestamps, duration, and filament used. Entries it has already imported for that printer and model are skipped, which makes re-running safe but also means repeat prints of one filename only produce a single record. Treat it as a one-off backfill for work you did before the library existed. The other providers do not expose a history feed to import from.

Do failed prints show up in the totals?

In the history and on the model, yes. In the Statistics totals, no, because those sum completed jobs only. A model’s page will tell you it failed twice out of nine attempts, while the month’s filament and cost figures cover the seven that finished. For a hobby record that is usually what you want. For a quote it is not, because failures consume filament and machine hours that a customer’s price has to absorb, so track that overhead separately and treat the dashboard as a floor rather than a total.

Where do I see cost per revision rather than per model?

In the revision compare view. Pick two revisions of a model and the outcome rows under the settings comparison give each one its print count, completed and failed counts, success rate, average actual time, total actual filament, and total actual cost. Per-model figures cover every slice of the part together, which hides the case you usually care about, where one revision is cheap and reliable and another quietly fails a third of the time.

Sources

For the view across every machine at once, rather than per model, managing multiple printers from one dashboard covers the live printer list and the aggregate statistics page.