============== Using Auditing ============== Substance D keeps an audit log of all meaningful operations performed against content if you have an audit database configured. At the time of this writing, "meaningful" is defined as: - When an ACL is changed. - When a resource is added or removed. - When a resource is modified. The audit log is of a fixed size (currently 1,000 items). When the audit log fills up, the oldest audit event is thrown away. Currently we don't have an archiving mechanism in place to keep around the items popped off the end of the log when it fills up; this is planned. You can extend the auditing system by using the :class:`substanced.audit.AuditLog`, writing your own events to the log. Configuring the Audit Database ============================== In order to enable auditing, you have to add an ``audit`` database to your Substance D configuration. This means adding a key to your application's section in the ``.ini`` file associated with the app:: zodbconn.uri.audit = An example of "some ZODB URI" above might be (for a FileStorage database, if your application doesn't use multiple processes):: zodbconn.uri.audit = file://%(here)s/auditlog.fs Or if your application uses multiple processes, use a ZEO URL. The database cannot be your main database. The reason that the audit database must live in a separate ZODB database is that we don't want undo operations to undo the audit log data. Note that if you do not configure an audit database, real-time SDI features such as your folder contents views updating without a manual refresh will not work. Once you've configured the audit database, you need to add an audit log object to the new database. You can do this using pshell:: [chrism@thinko sdnet]$ bin/pshell etc/development.ini Python 3.3.2 (default, Jun 1 2013, 04:46:52) [GCC 4.6.3] on linux Type "help" for more information. Environment: app The WSGI application. registry Active Pyramid registry. request Active request object. root Root of the default resource tree. root_factory Default root factory used to create `root`. >>> from substanced.audit import set_auditlog >>> set_auditlog(root) >>> import transaction; transaction.commit() Once you've done this, the "Auditing" tab of the root object in the SDI should no longer indicate that auditing is not configured. Viewing the Audit Log ===================== The root object will have a tab named "Auditing". You can view the currently active audit log entries from this page. Accessing this tab requires the ``sdi.view-auditlog`` permission. Adding an Audit Log Entry ========================= Here's an example of adding an audit log entry of type ``NailsFiled`` to the audit log: .. code-block:: python from substanced.util import get_oid, get_auditlog def myview(context, request): auditlog = get_auditlog(context) auditlog.add('NailsFiled', get_oid(context), type='fingernails') ... .. warning:: If you don't have an audit database defined, the :func:`~substanced.util.get_auditlog` API will return ``None``. This will add a``NailsFiled`` event with the payload ``{'type':'fingernails'}`` to the audit log. The payload will also automatically include a UNIX timestamp as the key ``time``. The first argument is the audit log typename. Audit entries of the same kind should share the same type name. It should be a string. The second argument is the oid of the content object which this event is related to. It may be ``None`` indicating that the event is global, and unrelated to any particular piece of content. You can pass any number of keyword arguments to :meth:`substanced.audit.AuditLog.add`, each will be added to the payload. Each value supplied as a keyword argument *must* be JSON-serializable. If one is not, you will receive an error when you attempt to add the event. Using The ``auditstream-sse`` View ================================== If you have auditing enabled, you can use a view named ``auditstream-sse`` against any resource in your resource tree using JavaScript. It will return an event stream suitable for driving an HTML5 ``EventSource`` (an HTML 5 feature, see http://www.html5rocks.com/en/tutorials/eventsource/basics/ for more information). The event stream will contain auditing events. This can be used for progressive enhancement of your application's UI. Substance D's SDI uses it for that purpose. For example, when an object's ACL is changed, a user looking at the "Security" tab of that object in the SDI will see the change immediately, rather than upon the next page refresh. Obtain events for the context of the view only:: var source = new EventSource( "${request.sdiapi.mgmt_path(context, 'auditstream-sse')}"); Obtain events for a single OID unrelated to the context:: var source = new EventSource( "${request.sdiapi.mgmt_path(context, 'auditstream-sse', query={'oid':'12345'})}"); Obtain events for a set of OIDs:: var source = new EventSource( "${request.sdiapi.mgmt_path(context, 'auditstream-sse', query={'oid':['12345', '56789']})}"); Obtain all events for all oids:: var source = new EventSource( "${request.sdiapi.mgmt_path(context, 'auditstream-sse', query={'all':'1'})}"); The executing user will need to possess the ``sdi.view-auditstream`` permission against the context on which the view is invoked. Each event payload will contain detailed information about the audit event as a string which represents a JSON dictionary. See the ``acl.pt`` template in the ``substanced/sdi/views/templates`` directory of Substance D to see a "real-world" usage of this feature.