{"id":26611525,"url":"https://github.com/ioncache/dbix-class-auditlog","last_synced_at":"2025-08-08T18:50:34.838Z","repository":{"id":56830467,"uuid":"3431615","full_name":"ioncache/DBIx-Class-AuditLog","owner":"ioncache","description":"Simple activity audit logging for DBIx::Class","archived":false,"fork":false,"pushed_at":"2016-10-03T07:53:12.000Z","size":194,"stargazers_count":9,"open_issues_count":7,"forks_count":10,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-10T01:07:43.259Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://metacpan.org/module/DBIx::Class::AuditLog","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ioncache.png","metadata":{"files":{"readme":"README.pod","changelog":"CHANGES","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-02-13T16:18:40.000Z","updated_at":"2014-09-09T00:42:28.000Z","dependencies_parsed_at":"2022-09-09T18:01:04.879Z","dependency_job_id":null,"html_url":"https://github.com/ioncache/DBIx-Class-AuditLog","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/ioncache/DBIx-Class-AuditLog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioncache%2FDBIx-Class-AuditLog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioncache%2FDBIx-Class-AuditLog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioncache%2FDBIx-Class-AuditLog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioncache%2FDBIx-Class-AuditLog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ioncache","download_url":"https://codeload.github.com/ioncache/DBIx-Class-AuditLog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ioncache%2FDBIx-Class-AuditLog/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260328920,"owners_count":22992793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-24T02:49:10.328Z","updated_at":"2025-06-17T09:33:49.984Z","avatar_url":"https://github.com/ioncache.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"=head1 NAME\n\nDBIx::Class::AuditLog - Simple activity audit logging for DBIx::Class\n\n=head1 SYNOPSIS\n\nNOTE: As of v0.5.0 some of the foreign key column names are changed and 'quote_names' is no longer enabled by default. This is to ensure that any of the table or column names used by the Audit Log don't conflict with any reserved words from any database.  An update_reserved_columns.pl script has been included in the /utils folder of the package to help with upgrading.  Sorry for the inconvenience.  If this script fails for you, then you may need to add specific sql to it for your particular brand of DB.\n\nEnable the AuditLog schema component in your L\u003cDBIx::Class::Schema\u003e class file:\n\n    package My::Schema;\n    use base qw/DBIx::Class::Schema/;\n\n    __PACKAGE__-\u003eload_components(qw/Schema::AuditLog/);\n\nEnable the AuditLog component in your the individual L\u003cDBIx::Class\u003e table class files that you want to enable logging on:\n\n    package My::Schema::Result::Table\n    use base qw/DBIx::Class::Core/;\n\n    __PACKAGE__-\u003eload_components(qw/AuditLog/);\n\nIf you want to use methods created by L\u003cDBIx::Class::Relationship::Base\u003e, like \"add_to_$rel\" or \"set_$rel\",\nif you are planing to use L\u003cDBIx::Class::ResultSet/delete\u003e or L\u003cDBIx::Class::ResultSet/update\u003e or if you use\nmodules which make use of these methods (like L\u003cHTML::FormHandler\u003e or L\u003cDBIx::Class::ResultSet::RecursiveUpdate\u003e,\nload the AuditLog-component in your ResultSet classes:\n\n    package My::Schema::ResultSet::Table;\n\n    use base 'DBIx::Class::ResultSet';\n\n    __PACKAGE__-\u003eload_components('ResultSet::AuditLog');\n\n    1;\n\nIf you need auditing in all your tables, an alternative way is to set \"DBIC::ResultSet::AuditLog\" as your\ndefault resultset class in load_components. See L\u003cDBIx::Class::ResultSet::AuditLog\u003e for details.\n\n\nIn your application wrap any insert/update/delete in a transaction to have audit logging activated:\n\n    $my_schema-\u003etxn_do(\n        sub {\n            $my_row-\u003eupdate({ ... });\n        }\n    );\n\nOptionally pass an extra hashref to the txn_do method to indicate a user (or user_id) and/or a description for the transaction:\n\n    $my_schema-\u003etxn_do(\n        sub {\n            $my_row-\u003eupdate({ ... });\n        },\n        {\n            user =\u003e 'username_or_id', # optional\n            description =\u003e 'description of transaction' # optional\n        }\n    );\n\nThe user/user_id will be stored in AuditLogUser-\u003ename.\n\n=head1 DESCRIPTION\n\nDBIx::Class::AuditLog is meant for tracking changes made to specific tables in your database.\n\nAny insert/update/delete that requires auditing must be wrapped in a L\u003c\"txn_do\"|DBIx::Class::Schema/\"txn_do\"\u003e statement.\n\nTransactions are saved as Changesets.  Each Changeset can have many Actions.  An Action can be of type insert/update/delete.  Actions can have many Changes. Changes show the data that was changed during an action.\n\nBy default all updated columns will be audited in any table where the AuditLog component is loaded.\n\n=head1 ADDITIONAL DBIC COLUMN ATTRIBUTES\n\nIndividual columns can have additional attributes added to change the Audit Log functionality.\n\n=head2 audit_log_column\n\nOn an individual column basis you can disable auditing by setting 'audit_log_column' to 0:\n\n    __PACKAGE__-\u003eadd_columns(\n      \"admin_id\",\n      { data_type =\u003e \"integer\", is_auto_increment =\u003e 1, is_nullable =\u003e 0, audit_log_column =\u003e 0 },\n      \"admin_name\",\n      { data_type =\u003e \"varchar\", is_nullable =\u003e 0, size =\u003e 20 },\n      \"admin_pasword\",\n      { data_type =\u003e \"varchar\", is_nullable =\u003e 0, size =\u003e 20 },\n    );\n\nIf you are using a DBIx::Class generated schema, and don't want to modify the column defintions directly, you can add the following to the editable portion of the Result Class file:\n\n    __PACKAGE__-\u003eadd_columns(\n        \"+admin_id\",\n        { audit_log_column =\u003e 0, }\n    );\n\n=head2 force_audit_log_column\n\nBy default, columns are only audited if their value changed.\nIt is possible to force auditing on a per-column basis by setting\n'force_audit_log_column' to 1:\n\n    __PACKAGE__-\u003eadd_columns(\n        \"+admin_id\",\n        { force_audit_log_column =\u003e 1, }\n    );\n\nIf auditing is forced for a column, the 'audit_log_column' attribute is ignored.\n\n=head2 modify_audit_value\n\nIt is possible to modify the values stored by DBIC::AuditLog on a per-column basis\nby setting the 'modify_audit_value' attibute to either a CodeRef, a method\nname or any true value. The configured code will be run as an object method of\nthe current DBIC::Result object, and expects the original value as parameter.\n\nIf 'modify_audit_value' is set to a true value which is NOT a method in the\ncurrent objects class, AuditLog will look for a method called\n'modify_audit_$colname', where $colname is the name of the corresponding column.\n\nNote: AuditLog will simply die if it can not find the modification method while\n'modify_audit_value' is true.\n\nThe following examples have the same result:\n\npassing a coderef:\n\n    __PACKAGE__-\u003eadd_columns(\n        \"+name\",\n        { modify_audit_value =\u003e sub{\n        my ($self, $value) = @_;\n        $value =~ tr/A-Z/a-z/;\n        return $value;\n    }, }\n    );\n\npassing a method name:\n\n    __PACKAGE__-\u003eadd_columns(\n        \"+name\",\n        { modify_audit_value =\u003e 'to_lowercase'},\n    );\n\n    sub to_lowercase{\n        my ($self, $value) = @_;\n        $value =~ tr/A-Z/a-z/;\n        return $value;\n    }\n\npassing a true value which is NOT a method name:\n\n    __PACKAGE__-\u003eadd_columns(\n        \"+name\",\n        { modify_audit_value =\u003e 1},\n    );\n\n    sub modify_audit_name{\n        my ($self, $value) = @_;\n        $value =~ tr/A-Z/a-z/;\n        return $value;\n    }\n\n=head1 TABLE STRUCTURE\n\nThe AuditLog schema is a self-contained schema that keeps no relationships to your main schema.\n\nThe AuditLog schema consists of 6 tables:\n\n    +-------------------------+\n    | Tables_audit_log_schema |\n    +-------------------------+\n    | audit_log_action        |\n    | audit_log_change        |\n    | audit_log_changeset     |\n    | audit_log_field         |\n    | audit_log_table         |\n    | audit_log_user          |\n    +-------------------------+\n\n=over 4\n\n=item User\n\nThe L\u003cAuditLogUser|DBIx::Class::Schema::AuditLog::Structure::User\u003e table contains a unique list of users that have executed transactions.  The 'name' field is used to store the User identifier.  This could be used for a user's name or id or other unique identifier as needed.\n\nThis table does not get a relationship to any table in your main schema.\n\n    mysql\u003e select * from audit_log_user order by id;\n    +----+---------------------+\n    | id | name                |\n    +----+---------------------+\n    |  1 | TestAdminUser       |\n    |  2 | YetAnotherAdminUser |\n    |  3 | ioncache            |\n    |  4 | markj               |\n    +----+---------------------+\n    4 rows in set (0.01 sec)\n\n=item Changeset\n\nAn L\u003cAuditLogChangeset|DBIx::Class::Schema::AuditLog::Structure::Changeset\u003e is an identifier for a transaction.  It can have many L\u003cActions|DBIx::Class::Schema::AuditLog::Structure::Action\u003e.  It can optionally be owned by a L\u003cUser|DBIx::Class::Schema::AuditLog::Structure::User\u003e.  And optionally have a description.\n\n    mysql\u003e select * from audit_log_changeset order by id;\n    +----+----------------------------------------------+---------------------+---------+\n    | id | description                                  | created_on          | user_id |\n    +----+----------------------------------------------+---------------------+---------+\n    |  1 | adding new user: JohnSample                  | 2012-06-22 17:16:25 |       1 |\n    |  2 | updating username: JaneSample                | 2012-06-22 17:16:25 |       1 |\n    |  3 | delete user: JohnSample                      | 2012-06-22 17:16:25 |       2 |\n    |  4 | adding new user: TehPwnerer -- no admin user | 2012-06-22 17:16:25 |    NULL |\n    |  5 | multi-action changeset                       | 2012-06-22 17:16:25 |       3 |\n    |  6 | NULL                                         | 2012-06-22 17:16:25 |       4 |\n    +----+----------------------------------------------+---------------------+---------+\n    6 rows in set (0.00 sec)\n\n=item Action\n\nAn L\u003cAuditLogAction|DBIx::Class::Schema::AuditLog::Structure::Action\u003e is an insert/update/delete belonging to a L\u003cChangeset|DBIx::Class::Schema::AuditLog::Structure::Changeset\u003e.  It is also owned by L\u003cTable|DBIx::Class::Schema::AuditLog::Structure::AuditedTable\u003e.\n\nIf the corresponding table has more than one primary key, the pk-values stored in 'audited_row' are joined with a '-'.\n(See action with id 11 below.)\n\n    mysql\u003e select * from audit_log_action order by id;\n    +----+--------------+------------------+-------------+---------------+\n    | id | changeset_id | audited_table_id | audited_row | action_type   |\n    +----+--------------+------------------+-------------+---------------+\n    |  1 |            1 |                1 |           8 |        insert |\n    |  2 |            2 |                1 |           7 |        update |\n    |  3 |            3 |                1 |           7 |        delete |\n    |  4 |            4 |                1 |           9 |        insert |\n    |  5 |            5 |                1 |          10 |        insert |\n    |  6 |            5 |                1 |          11 |        insert |\n    |  7 |            5 |                1 |          11 |        update |\n    |  8 |            5 |                1 |           9 |        update |\n    |  9 |            6 |                1 |          13 |        insert |\n    | 10 |            6 |                1 |          13 |        update |\n    | 11 |            7 |                2 |        3-10 |        insert |\n    +----+--------------+------------------+-------------+---------------+\n    10 rows in set (0.00 sec)\n\n=item Change\n\nAn L\u003cAuditLogChange|DBIx::Class::Schema::AuditLog::Structure::Change\u003e contains changed data for one AuditLogField in an AuditLogAction.  The original value is stored in the old_value field and the new value is stored in the new_value field.\n\n    mysql\u003e select * from audit_log_change order by id;\n    +----+-----------+----------+--------------+--------------+\n    | id | action_id | field_id | old_value    | new_value    |\n    +----+-----------+----------+--------------+--------------+\n    |  1 |         1 |        1 | NULL         | JohnSample   |\n    |  2 |         1 |        2 | NULL         | 8            |\n    |  3 |         1 |        3 | NULL         | 999-888-7777 |\n    |  4 |         3 |        1 | JohnSample   | NULL         |\n    |  5 |         3 |        2 | 7            | NULL         |\n    |  6 |         3 |        3 | 999-888-7777 | NULL         |\n    |  7 |         4 |        1 | NULL         | TehPnwerer   |\n    |  8 |         4 |        2 | NULL         | 9            |\n    |  9 |         4 |        3 | NULL         | 999-888-7777 |\n    | 10 |         5 |        1 | NULL         | Superman     |\n    | 11 |         5 |        2 | NULL         | 10           |\n    | 12 |         5 |        3 | NULL         | 123-456-7890 |\n    | 13 |         6 |        1 | NULL         | Spiderman    |\n    | 14 |         6 |        2 | NULL         | 11           |\n    | 15 |         6 |        3 | NULL         | 987-654-3210 |\n    | 16 |         8 |        1 | TehPnwerer   | TehPwnerer   |\n    | 17 |         8 |        3 | 999-888-7777 | 416-123-4567 |\n    | 18 |         9 |        1 | NULL         | Drunk Hulk   |\n    | 19 |         9 |        2 | NULL         | 13           |\n    | 20 |         9 |        3 | NULL         | 123-456-7890 |\n    +----+-----------+----------+--------------+--------------+\n    20 rows in set (0.00 sec)\n\n=item AuditedTable\n\nAn L\u003cAuditLogAuditedTable|DBIx::Class::Schema::AuditLog::Structure::AuditedTable\u003e contains a unique list of tables that are being tracked.  The name field contains the name of a table from your database.  AuditLogAuditedTable rows are added as needed whenever an insert/update/date occurs.\n\nNote: at least for DB2, the table name will have the schema name added as well, eg., myschema.foo for the foo table in schema myschema.\n\n    mysql\u003e select * from audit_log_table order by id;\n    +----+------+\n    | id | name |\n    +----+------+\n    |  1 | user |\n    +----+------+\n    1 row in set (0.00 sec)\n\n=item Field\n\nAn L\u003cAuditLogField|DBIx::Class::Schema::AuditLog::Structure::Field\u003e contains a unique list of fields for each table that is being audited.  The name field contains the name of a field from a specific table inyour database.  AuditLogField rows are added as needed whenever an insert/update/date occurs.\n\n    mysql\u003e select * from audit_log_field order by id;\n    +----+------------------+-------+\n    | id | audited_table_id | name  |\n    +----+------------------+-------+\n    |  1 |                1 | name  |\n    |  2 |                1 | id    |\n    |  3 |                1 | phone |\n    +----+------------------+-------+\n    3 rows in set (0.00 sec)\n\n=back\n\n=head1 DEPLOYMENT\n\nTo deploy an AuditLog schema, load your main schema, and then run the deploy command on the audit_log_schema:\n\n    my $schema = AuditTest::Schema-\u003econnect( \"DBI:mysql:database=audit_test\",\n        \"root\", \"somepassword\", { RaiseError =\u003e 1, PrintError =\u003e 0 } );\n\n    $schema-\u003eaudit_log_schema-\u003edeploy;\n\nThe db user that is deploying the schema must have the correct create table permissions.\n\nNote: this should only be run once.\n\n=head1 METHODS\n\n=head2 audit_log_schema\n\n=over 4\n\n=item Returns: DBIC schema\n\n=back\n\nThe Audit Log schema can be accessed from your main schema by calling the audit_log_schema method.\n\n    my $al_schema = $schema-\u003eaudit_log_schema;\n\n=head2 get_changes\n\n=over 4\n\n=item Required: id, table\n\n=item Optional: action_type, change_order, field, created_on\n\n=item Returns: DBIC resultset\n\n=back\n\nA convenience method for reading changes from the Audit Log.\n\n    my $al_schema = $schema-\u003eaudit_log_schema;\n    my $changes = $al_schema-\u003eget_changes({\n        id           =\u003e 1,\n        table        =\u003e 'foo',\n        field        =\u003e 'bar',           # optional\n        action_type  =\u003e 'insert',        # optional, 1 of insert, update, delete\n        created_on   =\u003e { '\u003e=', $time }, # optional, $time must be a DateTime object,\n        change_order =\u003e 'asc',           # optional, 1 of asc, desc\n    });\n\n=head1 TODO\n\n=over 4\n\n=item * add auto-deploy of schema if it doesn't exist\n\n=item * add more convenience method(s) for retrieving changes from the Audit Log schema (eg. get a changeset instead of just a list of changes)\n\n=back\n\n=head1 SEE ALSO\n\n=over 4\n\n=item * L\u003cDBIx::Class\u003e\n\n=item * L\u003cDBIx::Class::Journal\u003e\n\n=back\n\n=head1 ACKNOWLEDGEMENTS\n\nDevelopment time supported by OANDA L\u003cwww.oanda.com|http://www.oanda.com\u003e.\n\nMany ideas and code borrowed from L\u003cDBIx::Class::Journal\u003e.\n\n=head1 AUTHOR\n\nMark Jubenville (L\u003cioncache|mailto:ioncache@cpan.org\u003e)\n\n=head1 CONTRIBUTORS\n\nLukas Thiemeier (L\u003clukast|mailto:lukast@cpan.org\u003e)\n\nDimitar Petrov (L\u003cdpetrov|mailto:dcpetrov@cpan.org\u003e)\n\n=head1 COPYRIGHT AND LICENCE\n\nThis software is copyright (c) 2012 by Mark Jubenville.\n\nThis is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fioncache%2Fdbix-class-auditlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fioncache%2Fdbix-class-auditlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fioncache%2Fdbix-class-auditlog/lists"}