{"result":{"depiction_url":null,"edges":{"observes":{"objects":[{"created":"2026-09-09T13:47:47Z","object_id":{"id":1466,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_admin_menu","title":"observe_admin_menu\/3","uri":"https:\/\/zotonic.com\/id\/1466"},"seq":1},{"created":"2026-09-09T13:47:47Z","object_id":{"id":1468,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_acl_is_allowed","title":"observe_acl_is_allowed\/2","uri":"https:\/\/zotonic.com\/id\/1468"},"seq":2},{"created":"2026-09-09T13:47:47Z","object_id":{"id":1982,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_search_query","title":"observe_search_query\/2","uri":"https:\/\/zotonic.com\/id\/1982"},"seq":3},{"created":"2026-09-09T13:47:47Z","object_id":{"id":2517,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_content_security_report","title":"observe_content_security_report\/2","uri":"https:\/\/zotonic.com\/id\/2517"},"seq":4}],"predicate":{"id":2550,"is_a":["meta","predicate"],"name":"observes","title":{"_type":"trans","tr":{"en":"Observes"}},"uri":"https:\/\/zotonic.com\/id\/observes"}},"relation":{"objects":[{"created":"2020-05-30T05:47:50Z","object_id":{"id":1640,"is_a":["text","documentation","developerguide"],"name":"doc_developerguide_logging","title":{"_type":"trans","tr":{"en":"Write logs that explain an operation"}},"uri":"https:\/\/zotonic.com\/id\/1640"},"seq":1000000}],"predicate":{"id":303,"is_a":["meta","predicate"],"name":"relation","title":{"_type":"trans","tr":{"nl":"Relatie","en":"Relation"}},"uri":"http:\/\/purl.org\/dc\/terms\/relation"}},"subject":{"objects":[{"created":"2026-09-09T13:47:47Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-09-09T13:47:47Z","object_id":{"id":2566,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_operator","title":"Operator","uri":"https:\/\/zotonic.com\/id\/2566"},"seq":2},{"created":"2026-09-09T13:47:47Z","object_id":{"id":2607,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_logging_and_monitoring","title":"Logging and monitoring","uri":"https:\/\/zotonic.com\/id\/2607"},"seq":3},{"created":"2026-09-09T13:47:47Z","object_id":{"id":2635,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_module","title":"Module","uri":"https:\/\/zotonic.com\/id\/2635"},"seq":4},{"created":"2026-09-09T13:47:47Z","object_id":{"id":2657,"is_a":["categorization","keyword","keyword_task"],"name":"zotonic_topic_monitor","title":"Monitor","uri":"https:\/\/zotonic.com\/id\/2657"},"seq":5}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":1858,"is_a":["text","documentation","reference","module"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1858"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_module_mod_logging","page_url":{"en":"https:\/\/zotonic.com\/docs\/1858\/mod_logging","x-default":"https:\/\/zotonic.com\/docs\/1858\/mod_logging"},"preview_url":null,"resource":{"version":3358,"pivot_location_lat":null,"title":"mod_logging","is_authoritative":true,"body":"<p>Logs messages to the database and adds log views to the admin.<\/p>\n<h2>Logging messages to the database<\/h2>\n<p>To persist a log message in the database, enable mod_logging in your Zotonic site. Then, in your code, send the\n<code>#zlog{}<\/code> notification:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">-include_lib(&quot;zotonic_core\/include\/zotonic.hrl&quot;).\n\nsome_function() -&gt;\n    %% do some things\n\n    z_notifier:notify(\n        #zlog{\n            user_id = z_acl:user(Context),\n            props=#log_email{\n                severity = ?LOG_LEVEL_ERROR,\n                message_nr = MsgId,\n                mailer_status = bounce,\n                mailer_host = z_convert:ip_to_list(Peer),\n                envelop_to = BounceEmail,\n                envelop_from = &quot;&lt;&gt;&quot;,\n                to_id = z_acl:user(Context),\n                props = []\n        }},\n        Context\n    );\n<\/code><\/pre>\n<h2>E-mail log<\/h2>\n<p>The e-mail log is a separate view, which lists which email messages have been sent to which recipients. Any mail that\ngets sent gets logged here.<\/p>\n<p>This module stores selected log events in the site database and provides admin views and APIs to inspect those logs, including e-mail delivery log entries.<\/p>\n<h2>Accepted Events<\/h2>\n<p>This module handles the following notifier callbacks:<\/p>\n<ul><li><code>observe_acl_is_allowed<\/code>: Allow access to log resources only for users with the required log-view permissions.<\/li><li><code>observe_admin_menu<\/code>: Add log viewers and log configuration entries to the admin menu.<\/li><li><code>observe_search_query<\/code>: Provide module-specific search query handlers with ACL-aware filtering.<\/li><li><code>observe_tick_1h<\/code>: Delete expired log records during hourly maintenance.<\/li><li><code>observe_tick_1m<\/code>: Cleanup UI log de-duplication hashes and check the database pool health.<\/li><li><code>observe_tick_1s<\/code>: Fetch UI log messages from the circular buffer.<\/li><\/ul>\n<h2>Content-Security-Policy Log<\/h2>\n<p>The <code>mod_logging<\/code> module observes incoming Content-Security-Policy violation reports sent by browsers to the <code>controller_csp_report<\/code>\ncontroller, and logs them in the database with de-duplication based on the report content. Recent CSP violation reports can be viewed\nin the admin interface.<\/p>\n<p>The most recent CSP violation reports are kept in memory and can be retrieved via the <code>csp_reports\/1<\/code> API function, which is used by the\nadmin interface to display recent CSP violations without needing to query the database.<\/p>\n<p>Only the most recent 100 unique CSP violation reports are kept in memory to prevent unbounded growth in memory usage. When the limit is\nexceeded, the oldest report is dropped. For each unique CSP violation, the number of occurrences and the most recent occurrence timestamp\nare tracked, along with the original policy, the document URL, the source file and line number, and up to ten distinct report samples\nwhen available.<\/p>\n<h2>UI Log<\/h2>\n<p>Browser-side UI errors can be posted to this module and are stored in the <code>log_ui<\/code>\ntable for later inspection in the admin.<\/p>\n<p>To keep a sudden flood of client-side errors from overloading the site, incoming UI\nevents are first written to an in-memory ringbuffer with a fixed size. This means\nthe logging path stays bounded during overload: when the buffer fills up, older\nbuffered messages are overwritten instead of allowing unbounded growth in work or\nmemory usage.<\/p>\n<p>To reduce noise, near-simultaneous duplicate UI errors are also dropped for a short\nperiod. The duplicate detection key is based on the error <code>type<\/code>, <code>message<\/code>, <code>file<\/code>,\nand <code>line<\/code>, specifically so that the same site problem reported by many different\nusers is coalesced into a single logged event even when user ids, user agents, or\nother request-specific values differ.<\/p>","slug":"mod_logging","doc_module_config":[{"default":"false","description":"Disable the logging of errors in the browser UI. This is useful for performance reasons.","has_default":true,"key":"ui_log_disabled","module":"mod_logging","type":"boolean"}],"is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"8476fdadd8692ca4296b8c33e21b014361aaf02fc2287490f545517612863ccb","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":320,"is_a":["meta","category"],"name":"module","title":"Modules","uri":"https:\/\/test.zotonic.com\/id\/320"},"doc_source_path":"apps\/zotonic_mod_logging\/src\/mod_logging.erl","publication_start":"2023-01-30T19:24:00Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/apps\/zotonic_mod_logging\/src\/mod_logging.erl","pivot_location_lng":null,"doc_source_kind":"module","name":"doc_module_mod_logging","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2020-05-30T05:47:40Z","uri":null,"doc_status":"current","is_dependent":false,"erlang_app":"zotonic_mod_logging","publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"19073459ea19a1407318a37747716c6f8546ed23\n","creator_id":{"id":336,"is_a":["person","robot"],"name":"gitbot","title":"Git","uri":"https:\/\/zotonic.com\/id\/336"},"modified":"2026-10-07T21:20:04Z","title_slug":"mod_logging"},"uri":"https:\/\/zotonic.com\/id\/1858","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1858"}},"status":"ok"}