The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Tamper-Evident Audit Logging for Regulated Environments
Every analytical action taken in a consequential R environment should be documented — who did it, what they did, when, and why. In practice, almost none of it is.
regulog fills that gap. It records every action, change,
note, and decision into a tamper-evident, hash-chained audit trail
stored as newline-delimited JSON. Every entry is attributed to a named
user, time-stamped in UTC, and linked to the previous entry via SHA-256
— so any modification after the fact, however subtle, is detectable by
verify_log().
Works for regulated pharmaceutical environments (21 CFR Part 11, EU Annex 11), internal data pipelines, multi-user Shiny applications, and any context where accountability and traceability matter.
# Install from GitHub
pak::pak("repro-stats/regulog")library(regulog)
# Initialise a session
log <- regulog_init(
app = "primary-analysis",
version = "1.0.0",
user = "analyst",
path = "logs/audit.rlog"
)
# Log actions, changes, and decisions
log_action(log,
action = "data_read",
object = "adsl.sas7bdat",
reason = "Reading ADSL for primary efficacy analysis"
)
log_change(log,
object = "alpha",
field = "value",
before = "0.05",
after = "0.025",
reason = "Updated per protocol amendment 2"
)
log_note(log,
"Outlier in subject 01-042 retained per SAP section 8.3 —
discussed with medical monitor 2026-06-20"
)
# Log data reads, scoped to a block — read() is logged automatically
with_log(log, {
adsl <- read(haven::read_sas, "data/adsl.sas7bdat")
adae <- read(haven::read_sas, "data/adae.sas7bdat")
})
# Apply an electronic signature
log_signature(log,
"I certify this analysis is accurate and complete per SAP version 2.0")
# Verify tamper integrity
verify_log(log)
#> regulog: Log intact: 5 entries, chain unbroken
# Query the log
filter_log(log, type = "SIGNATURE")
filter_log(log, action = "data_read", from = "2026-06-01")
# Export for submission
export_audit_trail(log, format = "csv", signed = TRUE,
path = "outputs/audit_trail.csv")| Function | Purpose |
|---|---|
regulog_init() |
Initialise an audit logging session |
log_action() |
Log a discrete action |
log_change() |
Log a before/after field change |
log_note() |
Log a free-text annotation or analytical decision |
log_signature() |
Apply an electronic signature |
rl_read() |
Explicit, logged read of any data source |
with_log() |
Scoped convenience: read() calls inside the block log
automatically |
verify_log() |
Verify SHA-256 hash chain integrity |
filter_log() |
Query entries by type, user, action, or date |
export_audit_trail() |
Export to CSV or JSON, with optional signing |
regulog_shiny_init() |
Initialise inside a Shiny server function |
regulog_observer() |
Auto-log Shiny reactive input events |
Each entry hash is SHA-256 of all entry fields plus the prior hash:
h_0 = SHA256("GENESIS" | app | version | timestamp)
h_n = SHA256(entry_id | timestamp | app | version | user | type |
<payload fields> | h_{n-1})
Any modification to any field in any entry breaks the chain from that
point forward. verify_log() recomputes every hash and
reports the first broken link — and works offline from the
.rlog file, without an active R session.
| Type | Created by | Purpose |
|---|---|---|
ACTION |
log_action() |
Discrete events: reads, runs, approvals |
CHANGE |
log_change() |
Before/after field modifications |
NOTE |
log_note() |
Decisions and free-text rationale |
SIGNATURE |
log_signature() |
Named, dated, meaningful sign-off |
Deploying any software in a regulated environment requires documented evidence that it is installed correctly, operates as specified, and performs reliably under real-world conditions. This is the IQ/OQ/PQ qualification process required under 21 CFR Part 11, EU Annex 11, and GAMP 5 before a tool can be used in GxP workflows.
regulog ships pre-written, executable qualification
protocols. Instead of authoring validation documents from scratch — a
process that typically takes weeks of internal effort — your team runs
three commands and receives a complete, signed qualification record:
source(system.file("validation/IQ_regulog.R", package = "regulog"))
source(system.file("validation/OQ_regulog.R", package = "regulog"))
source(system.file("validation/PQ_regulog.R", package = "regulog"))Each protocol is self-contained and produces a pass/fail summary against explicit acceptance criteria:
| Protocol | What it covers | Tests |
|---|---|---|
| IQ — Installation Qualification | R version, package installation, dependency integrity, file system access | 10 |
| OQ — Operational Qualification | All 21 CFR §11.10 requirements: hash chain, tamper detection, user attribution, timestamps, export, signatures | 26 |
| PQ — Performance Qualification | End-to-end clinical workflows: data review, regulatory export, multi-user sessions, 500-entry load test, inspector query simulation | 7 |
Protocols are version-controlled alongside the package and updated with every release that affects qualified behaviour.
The qualification record produced by each run — including the platform, R version, date, and pass/fail status — can be retained as documented evidence of system qualification in your validated environment.
| Regulation | Clause | Coverage |
|---|---|---|
| 21 CFR Part 11 | §11.10(e) | Hash-chained, time-stamped, user-attributed entries |
| 21 CFR Part 11 | §11.10(b) | export_audit_trail() CSV and JSON |
| 21 CFR Part 11 | §11.100 | log_signature() signer identity |
| 21 CFR Part 11 | §11.200 | Signature components: identity, timestamp, meaning |
| EU Annex 11 | Clause 9 | Date, time, user, action on every entry |
| EU Annex 11 | Clause 11 | verify_log() periodic integrity evaluation |
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.