mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-23 16:32:19 +00:00
Compare commits
387 Commits
fbd63b5e4a
...
812c4c21a8
| Author | SHA1 | Date | |
|---|---|---|---|
| 812c4c21a8 | |||
| cdfe0117a0 | |||
| b43dbdecfb | |||
| 0cfb308fa2 | |||
| a0e09fb30f | |||
| dfae044f75 | |||
| 5e80593ae0 | |||
| 31f06f5724 | |||
| 159f534164 | |||
| ea0d687da0 | |||
| ce87e32837 | |||
| 866e374ac8 | |||
| aaba931db6 | |||
| 04f7742238 | |||
| cf23bb6dbe | |||
| bf27dacf23 | |||
| 0a9bcd696b | |||
| 8fb9beb008 | |||
| 5514009abe | |||
| c17883262a | |||
| 5476a64478 | |||
| 685797783c | |||
| 11b49208b2 | |||
| 18dc8d5860 | |||
| 18f6bf9eb5 | |||
| 958a7fd26f | |||
| 1124868bd8 | |||
| c800042e46 | |||
| fe7665b9f6 | |||
| 93cadcc7f1 | |||
| 480c5ad602 | |||
| 5720ba6203 | |||
| 9630c6cc3b | |||
| 6eec61eb2d | |||
| 3a216a2ada | |||
| b0364fdd51 | |||
| 0b2e35d138 | |||
| 6dc54379ea | |||
| 458e3a14b3 | |||
| e3c7e00b1e | |||
| 2fd1290179 | |||
| f2b90b44e6 | |||
| cf2c8cdca6 | |||
| 4e964245d5 | |||
| cc3d1b1f1c | |||
| e5140181ba | |||
| 2bb9b20aa4 | |||
| 32cbc2e079 | |||
| 62117a4a69 | |||
| bba206be78 | |||
| 22f5204262 | |||
| 5bb5a75ea7 | |||
| 6d1261f02b | |||
| 33fc929dc6 | |||
| c990a890f9 | |||
| 676317aae7 | |||
| 7f57521e05 | |||
| 9b3533de7b | |||
| e01f7e977e | |||
| 1a2aee4a7c | |||
| 571ae622d0 | |||
| 475b15c41f | |||
| 0eeb3f9811 | |||
| 0b8fbe53dd | |||
| 8dab08b85d | |||
| 5edd853fc5 | |||
| 5957e37720 | |||
| 8cf4eba223 | |||
| 754a878cd8 | |||
| 1073559f6a | |||
| 20e08efb78 | |||
| 64dfc36931 | |||
| d46e90fcf5 | |||
| 891aa83e01 | |||
| 97f6ae969d | |||
| 93fc54226d | |||
| 4421eb985d | |||
| 96c4cc1f88 | |||
| 415fc8d98e | |||
| d89a629f14 | |||
| 83c31f31b2 | |||
| 93afc5fe45 | |||
| a7e9731571 | |||
| 83e1accc8e | |||
| 888581e44a | |||
| 2ecf88d866 | |||
| 19befe9418 | |||
| dcbc2422c6 | |||
| 5bb34b4e66 | |||
| 3fcdf8f64a | |||
| 674e949f96 | |||
| bbc9afbc47 | |||
| e386ef8b28 | |||
| af9e4e853a | |||
| eb3ec42a59 | |||
| 54fdff3317 | |||
| ded41de176 | |||
| c12af269dc | |||
| 03079797f2 | |||
| f6fc9c4201 | |||
| d94b415cb0 | |||
| 4dd1e5a33d | |||
| 54e695942f | |||
| 4889f2b4b8 | |||
| 58d1e622a0 | |||
| af1fc95a3c | |||
| 20919618ce | |||
| 35e87f1761 | |||
| 4b043bc52e | |||
| 296901d2ba | |||
| c78669393c | |||
| 9162b37acd | |||
| d777496d51 | |||
| 44903d113d | |||
| feb786298f | |||
| f91bcc827e | |||
| da1e9c0359 | |||
| acb4a13f14 | |||
| b320b4f1fc | |||
| 8715949242 | |||
| 70c2bad4b1 | |||
| 83b0a2ac3c | |||
| 5ded4439b0 | |||
| 556ee967b8 | |||
| 72e29f5b69 | |||
| 57b1dfb127 | |||
| 4521961227 | |||
| a164678654 | |||
| 50afeacff6 | |||
| 98e514821f | |||
| 97feb57cd7 | |||
| 9c1787e700 | |||
| 7ba66e82ae | |||
| c316c65027 | |||
| 4b68ae27f1 | |||
| 38a5b056b8 | |||
| f636c2df60 | |||
| a66a876659 | |||
| f8192ab677 | |||
| 82200c61fb | |||
| 43e343158e | |||
| 3a2817969a | |||
| 1b508dfc11 | |||
| 959e553648 | |||
| 1f3da3e6ba | |||
| a2b37dfe53 | |||
| 6c5f4aaa0e | |||
| 3ba590a4b0 | |||
| 302e11218c | |||
| b2a1f407ec | |||
| 24c20c16be | |||
| 254a9e8086 | |||
| 0d2bfd7b6d | |||
| b570722434 | |||
| 58e219a512 | |||
| 88ee050529 | |||
| 6962c7f267 | |||
| e91aba10fc | |||
| 74f65b9585 | |||
| 5f722b0073 | |||
| fd9127c524 | |||
| 057eb7c1fc | |||
| 24897a45c9 | |||
| 9370c83ffc | |||
| 3a2d1d74c3 | |||
| ef4ffe4c5b | |||
| f69307ba61 | |||
| 2582876a08 | |||
| bf60ed95c3 | |||
| 39baad5e93 | |||
| 383d2e8dff | |||
| b57013202e | |||
| 13e8a8f484 | |||
| 3cd361dc4d | |||
| c262aefc28 | |||
| a195c93457 | |||
| efacaa6398 | |||
| af54743536 | |||
| 8d28c37e38 | |||
| c2fa1eea35 | |||
| d2612e5a67 | |||
| 49eaa67d57 | |||
| 6d98301daa | |||
| 5f46c04eea | |||
| b36ce021dc | |||
| ead2339ffd | |||
| cca3bc4500 | |||
| 9d55440df4 | |||
| 4077f3e538 | |||
| 658196cf69 | |||
| afe5c75537 | |||
| 2c552adfae | |||
| 1f61e4f66a | |||
| b68ca9eef5 | |||
| 9da5b9d659 | |||
| e97407c22c | |||
| 41fbfa5ac1 | |||
| 5c4e8ba889 | |||
| c96a592ef6 | |||
| eb4abeb81b | |||
| e2609a99b6 | |||
| 2709a482ec | |||
| 999dd5a297 | |||
| bd75deb879 | |||
| db5d95576d | |||
| f4af7bc04c | |||
| 8ce3b8fefd | |||
| da8e7483ed | |||
| e617f5bf6a | |||
| 9042562c54 | |||
| 4c5b6cc2cf | |||
| 1bb3e41a97 | |||
| 03e467d5f4 | |||
| 8c129e1c42 | |||
| a7e955e636 | |||
| 2eebef07db | |||
| 594be4aca5 | |||
| 9157346bf8 | |||
| 7474c07cbd | |||
| 11db21a500 | |||
| 17dbdfffde | |||
| a41515b8eb | |||
| 2f600c71c5 | |||
| e6dc5f52c0 | |||
| 7a0c741857 | |||
| e3b9cbb6e9 | |||
| 264ee05222 | |||
| 9ef2f984ca | |||
| 6a13f70242 | |||
| c767ebe512 | |||
| 402cb7e423 | |||
| 24fbc189ae | |||
| 935f320743 | |||
| d288216bcb | |||
| c3b54e3ae0 | |||
| 413610d5f2 | |||
| 33f71af500 | |||
| f7863083d4 | |||
| fcac1d7993 | |||
| 0bdbe942dd | |||
| 1645bcb66c | |||
| 112edbf8ae | |||
| 8084d0a0cc | |||
| d23e326315 | |||
| e38b0b4150 | |||
| ce89aaf96d | |||
| c53aa38b89 | |||
| 3e0c8a5f99 | |||
| f1250512eb | |||
| 26de2e81d6 | |||
| 9af489336d | |||
| d9b609d064 | |||
| 91b0900b11 | |||
| e13ea2209a | |||
| 034bd8fc99 | |||
| c911ad8345 | |||
| e776455861 | |||
| f824cbfa68 | |||
| abed0f00b8 | |||
| 75f1b457fa | |||
| e53555edb2 | |||
| 323d58059b | |||
| 8e409bbdf9 | |||
| b3fb59e6b5 | |||
| a6e9dd993f | |||
| 324ff47b10 | |||
| 8bf6ec8f52 | |||
| bf545b0e0c | |||
| d4db20fffc | |||
| 861adb7b5d | |||
| 1a33f5c95d | |||
| f50964f5a9 | |||
| ba72a021a8 | |||
| 5f0c7be4e4 | |||
| 4d2e3def14 | |||
| 2a9dbdcc01 | |||
| 47de8dc99a | |||
| 888be5b6fc | |||
| 15a9175cf4 | |||
| 3a68be920e | |||
| 699dd5ff96 | |||
| f8ca093e95 | |||
| be8b4f8626 | |||
| 3d88ac87a1 | |||
| 79529d748f | |||
| ab7cd62851 | |||
| e172e141e9 | |||
| d92155a727 | |||
| 78007a5b22 | |||
| e28dba0800 | |||
| 747f8e3d1b | |||
| 5917256fda | |||
| b937807136 | |||
| 5ce4c29760 | |||
| 911dcd840c | |||
| 4431e01dcb | |||
| d950f11b40 | |||
| 2845076b27 | |||
| 7207c07cbf | |||
| f19e9649af | |||
| c45ee1050f | |||
| d748bfc6e6 | |||
| 77d97cef5e | |||
| 3888d39bc0 | |||
| f7febb9f67 | |||
| 7440f1d328 | |||
| e035625fc1 | |||
| dae9d38a3f | |||
| ab45a9e4e3 | |||
| e27f5680e6 | |||
| 8196fe27b6 | |||
| 4b5456f646 | |||
| f4022ce95c | |||
| 7d2d20c31e | |||
| 1e568f55cd | |||
| 4e00c5eac5 | |||
| 01eb5c6f8d | |||
| dddad3d3d0 | |||
| 8427cc6cf3 | |||
| ce3eb06c1c | |||
| 61094732a8 | |||
| 342d08377f | |||
| 56ba583680 | |||
| 06541a578c | |||
| d47109aa54 | |||
| bb39091830 | |||
| c4ebf09a7b | |||
| 78fd2124da | |||
| 10555b3580 | |||
| 793e9bfc83 | |||
| 419b79ac50 | |||
| c8e4cee9d6 | |||
| a3ecb6676d | |||
| f1b7a86cf6 | |||
| 65605f6b59 | |||
| bf7512d113 | |||
| 6b59398bc6 | |||
| 1c83cf2ba1 | |||
| c5f7dda2aa | |||
| 18bc3dbdb0 | |||
| e1ba2fb835 | |||
| 45a596cce1 | |||
| 0df565d454 | |||
| 86b99fe004 | |||
| 1ebf31945c | |||
| a17f50db88 | |||
| 78ca9e60a9 | |||
| 138461871a | |||
| afce0c7ce2 | |||
| e34065441f | |||
| 78010b2524 | |||
| 8373c9c6c1 | |||
| 9a3fbcc793 | |||
| 038c37992f | |||
| 3dc5759a73 | |||
| 1c8a8c24a9 | |||
| 0f0b4c4321 | |||
| 248406ce75 | |||
| 212bb76b56 | |||
| 0dd4c6b080 | |||
| 27886e1eba | |||
| fd7defbb93 | |||
| 1a30562a28 | |||
| 0418fcab60 | |||
| 6ab828c4ce | |||
| a9725a8d33 | |||
| b60df648ff | |||
| a983af2e0b | |||
| 041385712b | |||
| 0566ebbabd | |||
| 839c03ec57 | |||
| 9c00ee9341 | |||
| dea63b1ed6 | |||
| d4ec733b64 | |||
| b47f95c918 | |||
| e01eed5c44 | |||
| 17573b9f9e | |||
| 3321ebef8b | |||
| 12f6ce4c2b | |||
| 17c1b95a61 | |||
| 3881ca505a | |||
| 554318a7b0 | |||
| 00e06c302f | |||
| cff282db2f | |||
| 13f0a24336 | |||
| 4e32a7350a | |||
| 76dbc421eb |
@@ -0,0 +1,61 @@
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: docs-pages
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build docs site
|
||||
env:
|
||||
DOCS_BASE: /
|
||||
run: npm run docs:build
|
||||
|
||||
- name: Configure Pages
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Upload Pages artifact
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/.vitepress/dist
|
||||
|
||||
deploy:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
+7
-1
@@ -16,9 +16,15 @@ desktop.ini
|
||||
*.log
|
||||
*.tmp
|
||||
*.bak
|
||||
node_modules/
|
||||
|
||||
# Dev Documentations
|
||||
docs/dev/*
|
||||
|
||||
# Docs site build artifacts
|
||||
docs/.vitepress/cache/
|
||||
docs/.vitepress/dist/
|
||||
docs/.vitepress/generated/
|
||||
|
||||
# vibecoding
|
||||
AGENTS/
|
||||
AGENTS/
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import { basename } from 'node:path'
|
||||
import { createMoonbitLanguageRegistration } from 'moonbit-syntax-highlighter'
|
||||
import { defineConfig, type DefaultTheme } from 'vitepress'
|
||||
|
||||
import { docsData } from './generated/docs-data.mjs'
|
||||
|
||||
type ApiDocEntry = {
|
||||
file: string
|
||||
text: string
|
||||
group: string
|
||||
category: string
|
||||
}
|
||||
|
||||
const repoSlug = process.env.GITHUB_REPOSITORY?.split('/')[1] ?? 'BitLogger'
|
||||
const docsBase = process.env.DOCS_BASE ?? (process.env.GITHUB_ACTIONS ? `/${repoSlug}/` : '/')
|
||||
const repository = 'https://github.com/Nanaloveyuki/BitLogger'
|
||||
|
||||
function splitWords(input: string): string[] {
|
||||
return input
|
||||
.split(/[^A-Za-z0-9]+/)
|
||||
.map(part => part.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
function formatWord(word: string): string {
|
||||
const lower = word.toLowerCase()
|
||||
if (lower === 'api') return 'API'
|
||||
if (lower === 'json') return 'JSON'
|
||||
if (lower === 'js') return 'JS'
|
||||
if (lower === 'wasm') return 'WASM'
|
||||
if (lower === 'llvm') return 'LLVM'
|
||||
return lower.charAt(0).toUpperCase() + lower.slice(1)
|
||||
}
|
||||
|
||||
function humanize(input: string): string {
|
||||
const words = splitWords(input)
|
||||
if (words.length === 0) return input
|
||||
return words.map(formatWord).join(' ')
|
||||
}
|
||||
|
||||
function readApiDocs(): ApiDocEntry[] {
|
||||
return docsData.api.entries.map(entry => ({
|
||||
file: entry.file,
|
||||
text: entry.title,
|
||||
group: entry.group,
|
||||
category: entry.category,
|
||||
}))
|
||||
}
|
||||
|
||||
function buildApiSidebar(): DefaultTheme.SidebarItem[] {
|
||||
const entries = readApiDocs()
|
||||
const sidebar: DefaultTheme.SidebarItem[] = [{ text: 'Overview', link: '/api/' }]
|
||||
const groups = new Map<string, Map<string, DefaultTheme.SidebarItem[]>>()
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.file === 'index.md') continue
|
||||
const group = groups.get(entry.group) ?? new Map<string, DefaultTheme.SidebarItem[]>()
|
||||
const categoryItems = group.get(entry.category) ?? []
|
||||
categoryItems.push({
|
||||
text: entry.text,
|
||||
link: `/api/${basename(entry.file, '.md')}`,
|
||||
})
|
||||
group.set(entry.category, categoryItems)
|
||||
groups.set(entry.group, group)
|
||||
}
|
||||
|
||||
if (groups.size === 1 && groups.has('api')) {
|
||||
const categories = groups.get('api')!
|
||||
for (const category of [...categories.keys()].sort((a, b) => humanize(a).localeCompare(humanize(b)))) {
|
||||
sidebar.push({
|
||||
text: humanize(category),
|
||||
collapsed: true,
|
||||
items: categories.get(category)!,
|
||||
})
|
||||
}
|
||||
return sidebar
|
||||
}
|
||||
|
||||
for (const group of [...groups.keys()].sort((a, b) => humanize(a).localeCompare(humanize(b)))) {
|
||||
const categories = groups.get(group)!
|
||||
sidebar.push({
|
||||
text: humanize(group),
|
||||
collapsed: true,
|
||||
items: [...categories.keys()]
|
||||
.sort((a, b) => humanize(a).localeCompare(humanize(b)))
|
||||
.map(category => ({
|
||||
text: humanize(category),
|
||||
collapsed: true,
|
||||
items: categories.get(category)!,
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
return sidebar
|
||||
}
|
||||
|
||||
function buildChangesSidebar(): DefaultTheme.SidebarItem[] {
|
||||
return [
|
||||
{ text: 'Overview', link: '/changes/' },
|
||||
{
|
||||
text: 'Versions',
|
||||
items: docsData.changes.map(item => ({ text: item.version, link: item.link })),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
title: 'BitLogger',
|
||||
description: 'Structured logging library docs for MoonBit.',
|
||||
base: docsBase,
|
||||
cleanUrls: true,
|
||||
srcExclude: ['dev/**'],
|
||||
lastUpdated: true,
|
||||
markdown: {
|
||||
languages: [createMoonbitLanguageRegistration()],
|
||||
},
|
||||
themeConfig: {
|
||||
siteTitle: 'BitLogger',
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'API', link: '/api/' },
|
||||
{ text: 'Changes', link: '/changes/' },
|
||||
{ text: 'Mooncake', link: 'https://mooncakes.io/docs/Nanaloveyuki/BitLogger' },
|
||||
],
|
||||
search: {
|
||||
provider: 'local',
|
||||
},
|
||||
socialLinks: [{ icon: 'github', link: repository }],
|
||||
editLink: {
|
||||
pattern: `${repository}/edit/main/docs/:path`,
|
||||
text: 'Edit this page on GitHub',
|
||||
},
|
||||
sidebar: {
|
||||
'/api/': buildApiSidebar(),
|
||||
'/changes/': buildChangesSidebar(),
|
||||
},
|
||||
footer: {
|
||||
message: 'Published from the repository docs folder with VitePress.',
|
||||
copyright: 'MIT',
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,219 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, shallowRef } from 'vue'
|
||||
import { withBase } from 'vitepress'
|
||||
|
||||
import { docsData } from '../../generated/docs-data.mjs'
|
||||
|
||||
const selectedGroup = shallowRef('all')
|
||||
const query = shallowRef('')
|
||||
|
||||
const groups = computed(() => docsData.api.groups)
|
||||
|
||||
const filteredGroups = computed(() => {
|
||||
const keyword = query.value.trim().toLowerCase()
|
||||
return groups.value
|
||||
.filter(group => selectedGroup.value === 'all' || group.id === selectedGroup.value)
|
||||
.map(group => ({
|
||||
...group,
|
||||
categories: group.categories
|
||||
.map(category => ({
|
||||
...category,
|
||||
entries: category.entries.filter(entry => {
|
||||
if (!keyword) return true
|
||||
const haystack = [entry.title, entry.description, entry.name, ...entry.keywords]
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
return haystack.includes(keyword)
|
||||
}),
|
||||
}))
|
||||
.filter(category => category.entries.length > 0),
|
||||
}))
|
||||
.filter(group => group.categories.length > 0)
|
||||
})
|
||||
|
||||
const resultCount = computed(() =>
|
||||
filteredGroups.value.reduce(
|
||||
(total, group) => total + group.categories.reduce((sum, category) => sum + category.entries.length, 0),
|
||||
0,
|
||||
),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="api-shell">
|
||||
<div class="api-toolbar">
|
||||
<label class="api-search">
|
||||
<span>Find API</span>
|
||||
<input v-model="query" type="search" placeholder="Search logger, sink, config, async...">
|
||||
</label>
|
||||
|
||||
<label class="api-filter">
|
||||
<span>Doc Group</span>
|
||||
<select v-model="selectedGroup">
|
||||
<option value="all">All groups</option>
|
||||
<option v-for="group in groups" :key="group.id" :value="group.id">
|
||||
{{ group.label }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="api-summary">
|
||||
<strong>{{ resultCount }}</strong>
|
||||
<span>matching API pages across {{ filteredGroups.length }} group views</span>
|
||||
</div>
|
||||
|
||||
<div class="api-groups">
|
||||
<article v-for="group in filteredGroups" :key="group.id" class="api-group-card">
|
||||
<header class="api-group-header">
|
||||
<div>
|
||||
<p class="api-group-kicker">{{ group.label }}</p>
|
||||
<h3>{{ group.entryCount }} APIs in this group</h3>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="api-category-grid">
|
||||
<section v-for="category in group.categories" :key="category.id" class="api-category-card">
|
||||
<h4>{{ category.label }}</h4>
|
||||
<p>{{ category.entries.length }} entries</p>
|
||||
<ul>
|
||||
<li v-for="entry in category.entries.slice(0, 8)" :key="entry.slug">
|
||||
<a :href="withBase(entry.link)">{{ entry.title }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a v-if="category.entries.length > 8" class="api-more" :href="withBase('/api/')">
|
||||
Browse {{ category.entries.length - 8 }} more in sidebar
|
||||
</a>
|
||||
</section>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.api-shell {
|
||||
margin: 1.5rem 0 2rem;
|
||||
}
|
||||
|
||||
.api-toolbar {
|
||||
display: grid;
|
||||
gap: 0.9rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.api-search,
|
||||
.api-filter {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.api-search span,
|
||||
.api-filter span {
|
||||
font-size: 0.78rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: #9b4d28;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.api-search input,
|
||||
.api-filter select {
|
||||
width: 100%;
|
||||
border-radius: 14px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 0.85rem 0.95rem;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.api-summary {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.65rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.api-summary strong {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.api-summary span {
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.api-groups {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.api-group-card {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 28px;
|
||||
padding: 1rem;
|
||||
background: linear-gradient(180deg, rgba(255, 251, 247, 0.96), rgba(246, 242, 236, 0.96));
|
||||
}
|
||||
|
||||
.api-group-header h3,
|
||||
.api-category-card h4,
|
||||
.api-category-card p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.api-group-kicker {
|
||||
margin: 0 0 0.25rem;
|
||||
color: #9b4d28;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.api-category-grid {
|
||||
display: grid;
|
||||
gap: 0.85rem;
|
||||
margin-top: 0.9rem;
|
||||
}
|
||||
|
||||
.api-category-card {
|
||||
border-radius: 20px;
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
border: 1px solid rgba(155, 77, 40, 0.12);
|
||||
padding: 0.95rem;
|
||||
}
|
||||
|
||||
.api-category-card p {
|
||||
margin-top: 0.25rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.api-category-card ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0.85rem 0 0;
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.api-category-card a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.api-more {
|
||||
display: inline-block;
|
||||
margin-top: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (min-width: 820px) {
|
||||
.api-toolbar {
|
||||
grid-template-columns: minmax(0, 2fr) minmax(220px, 0.8fr);
|
||||
}
|
||||
|
||||
.api-category-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,191 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { withBase } from 'vitepress'
|
||||
|
||||
import { docsData } from '../../generated/docs-data.mjs'
|
||||
|
||||
const topCategories = computed(() => docsData.api.categories.slice(0, 6))
|
||||
const recentChanges = computed(() => docsData.changes.slice(0, 4))
|
||||
const apiCount = computed(() => docsData.api.entries.filter(entry => entry.slug !== 'index').length)
|
||||
const groupCount = computed(() => docsData.api.groups.length)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="hub-grid">
|
||||
<article class="hub-panel hub-panel-accent">
|
||||
<p class="hub-eyebrow">Docs Hub</p>
|
||||
<h2 class="hub-title">Start from use case, not from filenames.</h2>
|
||||
<p class="hub-copy">
|
||||
Browse builders, runtime helpers, presets, sync logging, and async logging from one place.
|
||||
</p>
|
||||
<div class="hub-stats">
|
||||
<div>
|
||||
<strong>{{ apiCount }}</strong>
|
||||
<span>API pages</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ groupCount }}</strong>
|
||||
<span>doc groups</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ docsData.changes.length }}</strong>
|
||||
<span>release notes</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="hub-panel">
|
||||
<p class="hub-eyebrow">Popular Areas</p>
|
||||
<ul class="hub-chip-list">
|
||||
<li v-for="category in topCategories" :key="category.id">
|
||||
<a class="hub-chip" :href="withBase('/api/')">
|
||||
<span>{{ category.label }}</span>
|
||||
<small>{{ category.entryCount }}</small>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="hub-panel">
|
||||
<p class="hub-eyebrow">Release Trail</p>
|
||||
<ul class="hub-link-list">
|
||||
<li v-for="item in recentChanges" :key="item.version">
|
||||
<a :href="withBase(item.link)">Version {{ item.version }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.hub-grid {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
margin: 1.5rem 0 2rem;
|
||||
}
|
||||
|
||||
.hub-panel {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 24px;
|
||||
padding: 1.25rem;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(247, 245, 239, 0.95));
|
||||
box-shadow: 0 16px 40px rgba(62, 46, 31, 0.08);
|
||||
}
|
||||
|
||||
.hub-panel-accent {
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(191, 68, 32, 0.16), transparent 34%),
|
||||
linear-gradient(180deg, rgba(255, 250, 244, 0.98), rgba(247, 241, 232, 0.98));
|
||||
}
|
||||
|
||||
.hub-eyebrow {
|
||||
margin: 0 0 0.5rem;
|
||||
color: #9b4d28;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hub-title {
|
||||
margin: 0;
|
||||
font-size: 1.55rem;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.hub-copy {
|
||||
margin: 0.85rem 0 0;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.hub-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin-top: 1.15rem;
|
||||
}
|
||||
|
||||
.hub-stats strong,
|
||||
.hub-stats span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hub-stats strong {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.hub-stats span {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.hub-chip-list,
|
||||
.hub-link-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hub-chip-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 0.7rem;
|
||||
}
|
||||
|
||||
.hub-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
min-height: 56px;
|
||||
gap: 0.8rem;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-radius: 999px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid rgba(155, 77, 40, 0.14);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hub-chip span {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.hub-chip small {
|
||||
flex: 0 0 auto;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hub-chip-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.hub-link-list {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.hub-link-list a {
|
||||
color: var(--vp-c-brand-1);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (min-width: 860px) {
|
||||
.hub-grid {
|
||||
grid-template-columns: 1.35fr 1fr;
|
||||
}
|
||||
|
||||
.hub-panel-accent {
|
||||
grid-row: span 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.hub-stats {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,37 @@
|
||||
:root {
|
||||
--vp-c-brand-1: #b34a24;
|
||||
--vp-c-brand-2: #92381a;
|
||||
--vp-c-brand-3: #d06d39;
|
||||
--vp-c-brand-soft: rgba(176, 74, 36, 0.14);
|
||||
--vp-home-hero-name-color: #6b2f17;
|
||||
--vp-home-hero-text-color: #27170f;
|
||||
--vp-home-hero-tagline-color: #5f5249;
|
||||
--vp-font-family-base: "Segoe UI", "PingFang SC", "Hiragino Sans GB", sans-serif;
|
||||
--vp-font-family-mono: "Cascadia Mono", "JetBrains Mono", monospace;
|
||||
}
|
||||
|
||||
.VPContent {
|
||||
background:
|
||||
radial-gradient(circle at top right, rgba(208, 109, 57, 0.08), transparent 28%),
|
||||
radial-gradient(circle at left 20%, rgba(179, 74, 36, 0.06), transparent 22%);
|
||||
}
|
||||
|
||||
.VPHomeHero .name,
|
||||
.VPDoc h1,
|
||||
.VPDoc h2,
|
||||
.VPDoc h3 {
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.VPHomeHero .image-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vp-doc a {
|
||||
text-underline-offset: 0.18em;
|
||||
}
|
||||
|
||||
.vp-doc .custom-block,
|
||||
.vp-doc div[class*='language-'] {
|
||||
border-radius: 18px;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import DefaultTheme from 'vitepress/theme'
|
||||
import type { Theme } from 'vitepress'
|
||||
|
||||
import ApiOverview from './components/ApiOverview.vue'
|
||||
import HomeDocHub from './components/HomeDocHub.vue'
|
||||
|
||||
import './custom.css'
|
||||
|
||||
const theme: Theme = {
|
||||
extends: DefaultTheme,
|
||||
enhanceApp({ app }) {
|
||||
app.component('ApiOverview', ApiOverview)
|
||||
app.component('HomeDocHub', HomeDocHub)
|
||||
},
|
||||
}
|
||||
|
||||
export default theme
|
||||
+8
-5
@@ -3,7 +3,7 @@
|
||||
BitLogger is a structured logging library for MoonBit projects.
|
||||
|
||||
- [Mooncake package page](https://mooncakes.io/docs/Nanaloveyuki/BitLogger)
|
||||
- [Chinese README](../README.md)
|
||||
- [Chinese README](https://github.com/Nanaloveyuki/BitLogger/blob/main/README.md)
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -30,8 +30,9 @@ Use `Logger::new(...)` when you want to assemble custom sink graphs directly.
|
||||
|
||||
## Support Status
|
||||
|
||||
- Currently verified targets: `native`, `js`, `wasm`, `wasm-gc`
|
||||
- `llvm` is still treated as experimental in the current release context
|
||||
- Current local verification covers `native`, `js`, `wasm`, and `wasm-gc` for the main `src` package and `src-async`
|
||||
- `llvm` is still treated as experimental in the current release context and was not locally re-verified in the current environment
|
||||
- The source packages still declare `wasm` support alongside `native`, `llvm`, `js`, and `wasm-gc`; see [`target-verification.md`](./api/target-verification.md) for the current release-facing verification boundary
|
||||
- File output is a native capability; check `native_files_supported()` in cross-target code
|
||||
- `src-async` is available, while `examples/async_basic` is still shipped as a native entry example
|
||||
|
||||
@@ -56,7 +57,9 @@ Use `Logger::new(...)` when you want to assemble custom sink graphs directly.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [API index](./api/index.md)
|
||||
- [src package README](../src/README.mbt.md)
|
||||
- [API index](./api/index.md): canonical API reference, organized as one public API per file
|
||||
- [src package README](https://github.com/Nanaloveyuki/BitLogger/blob/main/src/README.mbt.md): package-level usage notes and target reminders
|
||||
- [`docs/changes/`](./changes/): versioned release notes and publish-facing change summaries
|
||||
- `docs/dev/`: developer reference material kept in the repository, intentionally excluded from the public static docs site
|
||||
|
||||
Common entry points: `text_console(...)`, `file(...)`, `with_queue(...)`, `build_logger(...)`, `build_async_logger(...)`
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
name: application-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
description: Application-facing alias for the runtime-sink async logger surface, preserving the same async calling semantics as AsyncLogger.
|
||||
key-word:
|
||||
- application
|
||||
- async
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Application-async-logger
|
||||
|
||||
`ApplicationAsyncLogger` is the application-facing async logger alias. It currently maps directly to `AsyncLogger[@bitlogger.RuntimeSink]` and keeps the same async lifecycle, state, and queue helper surface.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type ApplicationAsyncLogger = AsyncLogger[@bitlogger.RuntimeSink]
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `ApplicationAsyncLogger` - Application-facing name for the runtime-sink async logger shape.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This alias does not introduce a new runtime type or wrapper layer.
|
||||
- It preserves the same async lifecycle helpers such as `run()`, `shutdown()`, `pending_count()`, and `state()`.
|
||||
- Because it is `AsyncLogger[@bitlogger.RuntimeSink]`, the alias also keeps ordinary async logger composition and target behavior such as `with_target(...)`, `child(...)`, and per-call `log(..., target=...)` overrides.
|
||||
- In particular, `log(..., target=...)` can override the target for one call, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- Unlike the synchronous application alias, async `with_context_fields(...)` and `bind(...)` preserve the visible `ApplicationAsyncLogger` shape because shared fields are stored directly on the async logger value instead of being modeled as a separate sink wrapper.
|
||||
- Because this is only an alias, methods that are async on `AsyncLogger[@bitlogger.RuntimeSink]` remain async here as well.
|
||||
- The alias therefore keeps the same runtime-sink lifecycle, queue, failure-state, and runtime-dependent post-close semantics already documented on `AsyncLogger[@bitlogger.RuntimeSink]`.
|
||||
- In the current direct alias coverage, values built through `build_application_async_logger(...)` keep the same serialized state snapshot shape, queue counters, lifecycle flags, failure fields, and runtime-sink helper surface that the underlying runtime-sink async logger exposes directly.
|
||||
- When the value is built through `build_application_async_logger(...)`, the sync-first builder route also stays visible through the alias: any optional `LoggerConfig.queue` was already applied before async wrapping, and `logger.sink.kind` had already selected the concrete `RuntimeSink` variant before the application alias reused that value.
|
||||
- That includes queued runtime-sink behavior and file-backed runtime helpers when the configured sink path supports them.
|
||||
- Those helpers remain directly callable on `ApplicationAsyncLogger` itself; callers do not need an unwrap step to reach queue counters, lifecycle state, or `RuntimeSink` file helpers.
|
||||
- The alias exists to give application boot code a clearer public type name for the standard runtime-sink async logger.
|
||||
- Builders such as `build_application_async_logger(...)` and `parse_and_build_application_async_logger(...)` return this alias.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need An App-level Name For The Standard Async Runtime Logger
|
||||
|
||||
When application code wants a stable public type name for the runtime-sink async logger:
|
||||
```moonbit
|
||||
let logger : ApplicationAsyncLogger = build_application_async_logger(
|
||||
AsyncLoggerBuildConfig::new(logger=LoggerConfig::new(target="app.async")),
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the application alias keeps the same underlying async logger behavior while presenting an app-facing type name.
|
||||
|
||||
#### When Pass The Async Logger Through App-level APIs
|
||||
|
||||
When top-level boot code or services should expose an application-oriented async logger type:
|
||||
```moonbit
|
||||
async fn start_async(logger : ApplicationAsyncLogger) -> Unit {
|
||||
logger.run()
|
||||
}
|
||||
```
|
||||
|
||||
In this example, callers see the app-facing alias instead of the more explicit generic async logger spelling, while `run()` keeps its async calling contract.
|
||||
|
||||
And the inherited async logger target rules stay the same: `log(..., target=...)` can override the target per call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Direct Async Runtime Helpers On The Application Alias
|
||||
|
||||
When app code should inspect queue or file-backed runtime state without leaving the alias surface:
|
||||
```moonbit
|
||||
ignore(logger.pending_count())
|
||||
ignore(logger.state())
|
||||
```
|
||||
|
||||
In this example, lifecycle and queue helpers are called directly on `ApplicationAsyncLogger`.
|
||||
|
||||
And unlike `LibraryAsyncLogger[@bitlogger.RuntimeSink]`, no `to_async_logger()` unwrap is required first.
|
||||
|
||||
#### When Need A One-call Target Override Without Rebuilding The Alias
|
||||
|
||||
When app-level async code should keep the same alias value but emit one record under a different target:
|
||||
```moonbit
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="app.async.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `app.async.audit` only for that one call.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the alias value's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Shared Context On The Async Application Alias
|
||||
|
||||
When app-level async code should attach stable metadata to later queued records:
|
||||
```moonbit
|
||||
let contextual = logger.with_context_fields([@bitlogger.field("service", "billing")])
|
||||
```
|
||||
|
||||
In this example, the returned value still has the visible type `ApplicationAsyncLogger`.
|
||||
|
||||
And that shape preservation is intentional because async context binding updates stored logger metadata instead of changing the exposed sink type.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- Because this is only an alias, any runtime-sink limitations or target-specific async behavior still apply unchanged.
|
||||
|
||||
- If the value came from `build_application_async_logger(...)` or `parse_and_build_application_async_logger(...)`, the alias also does not undo the underlying sync-first sink selection; queued and file-backed runtime behavior still depend on the already-built `RuntimeSink` variant.
|
||||
|
||||
- If code needs a narrower public surface than the full async logger API, `LibraryAsyncLogger` is the better facade.
|
||||
|
||||
- If callers need queued runtime-sink helpers or file-backed runtime helpers, they remain directly available on this alias because no wrapper layer strips them away.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This alias is about naming and public intent, not a different async implementation.
|
||||
|
||||
2. Inherited `AsyncLogger` behavior stays unchanged on this alias, including target overrides on `log(...)` and derived target composition through `with_target(...)` and `child(...)`.
|
||||
|
||||
3. Use `build_application_async_logger(...)` or `parse_and_build_application_async_logger(...)` for the usual construction paths.
|
||||
|
||||
4. Use `ApplicationTextAsyncLogger` or `build_application_text_async_logger(...)` when application code should keep the narrower text-console sink type instead of the broader runtime-sink alias.
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: application-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260613
|
||||
description: Application-facing alias for the configured sync runtime logger surface, preserving the full ConfiguredLogger helper set.
|
||||
key-word:
|
||||
- application
|
||||
- facade
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Application-logger
|
||||
|
||||
`ApplicationLogger` is the application-facing sync logger alias. It currently maps directly to `ConfiguredLogger` and keeps the same runtime helper surface for sync logging, queue inspection, and file controls.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type ApplicationLogger = ConfiguredLogger
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `ApplicationLogger` - Application-facing name for the configured sync runtime logger shape.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This alias does not introduce a new runtime type or wrapper layer.
|
||||
- It preserves the same logging, queue, and file helper APIs exposed by `ConfiguredLogger`.
|
||||
- Because `ConfiguredLogger` is itself `Logger[RuntimeSink]`, the alias also keeps ordinary logger composition and write behavior such as `with_target(...)`, `child(...)`, and `log(..., target=...)`.
|
||||
- In particular, `log(..., target=...)` can override the target for one call, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- Like the underlying synchronous logger line, `with_context_fields(...)` and `bind(...)` do not preserve the alias spelling. They return a `Logger[ContextSink[RuntimeSink]]` shape because sync shared-field binding extends the sink pipeline instead of storing extra alias-level context metadata.
|
||||
- Because this is only an alias, the application-facing type does not hide any configured-runtime helpers or broader logger surface.
|
||||
- That means queue, drain, flush, and file runtime helpers remain directly callable on `ApplicationLogger` itself; callers do not need an unwrap step to reach the underlying configured runtime logger behavior.
|
||||
- The alias exists to give application boot code a clearer public entry name.
|
||||
- Builders such as `build_application_logger(...)` and `parse_and_build_application_logger(...)` return this alias.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need An App-level Name For The Configured Runtime Logger
|
||||
|
||||
When application code wants a stable public type name for the configured sync logger:
|
||||
```moonbit
|
||||
let logger : ApplicationLogger = build_application_logger(LoggerConfig::new(target="app"))
|
||||
```
|
||||
|
||||
In this example, the application alias keeps the same underlying runtime logger behavior while presenting an app-facing type name.
|
||||
|
||||
#### When Pass The Configured Logger Through App-level APIs
|
||||
|
||||
When top-level boot code or services should expose an application-oriented logger type:
|
||||
```moonbit
|
||||
fn start(logger : ApplicationLogger) -> Unit {
|
||||
logger.info("started")
|
||||
}
|
||||
```
|
||||
|
||||
In this example, callers see the app-facing alias instead of the lower-level `ConfiguredLogger` name.
|
||||
|
||||
And the same queue/file/runtime helpers remain directly callable because no narrowing wrapper is added.
|
||||
|
||||
#### When Need Direct Runtime Helpers On The Application Alias
|
||||
|
||||
When app code should inspect queue state or file controls without leaving the alias surface:
|
||||
```moonbit
|
||||
ignore(logger.pending_count())
|
||||
ignore(logger.flush())
|
||||
```
|
||||
|
||||
In this example, the runtime helpers are called directly on `ApplicationLogger`.
|
||||
|
||||
And unlike `LibraryLogger[RuntimeSink]`, no `to_logger()` unwrap is required first.
|
||||
|
||||
And the inherited logger target rules stay the same: `log(..., target=...)` can override the target per call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need A One-call Target Override Without Rebuilding The Alias
|
||||
|
||||
When app-level sync code should keep the same alias value but emit one record under a different target:
|
||||
```moonbit
|
||||
logger.log(Level::Error, "boom", target="app.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `app.audit` only for that one call.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the alias value's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Shared Context On The Sync Application Alias
|
||||
|
||||
When app-level sync code should attach stable metadata to later records:
|
||||
```moonbit
|
||||
let contextual = logger.with_context_fields([field("service", "billing")])
|
||||
```
|
||||
|
||||
In this example, the returned value has the visible type `Logger[ContextSink[RuntimeSink]]` rather than the alias name `ApplicationLogger`.
|
||||
|
||||
And that type-shape change is expected because sync context binding extends the sink pipeline.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- Because this is only an alias, any backend limitations of `ConfiguredLogger` still apply unchanged.
|
||||
|
||||
- If code needs a narrower public surface than the full configured runtime logger, `LibraryLogger` is the better facade.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This alias is about naming and public intent, not a different runtime implementation.
|
||||
|
||||
2. Inherited `Logger` behavior stays unchanged on this alias, including target overrides on `log(...)` and derived target composition through `with_target(...)` and `child(...)`.
|
||||
|
||||
3. Use `build_application_logger(...)` or `parse_and_build_application_logger(...)` for the usual construction paths.
|
||||
|
||||
4. Use `LibraryLogger` instead when a library boundary should intentionally hide configured-runtime helper methods behind a narrower facade.
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
name: application-text-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
description: Application-facing alias for the text-console async logger surface, preserving the full AsyncLogger helper set for the concrete text sink shape.
|
||||
key-word:
|
||||
- application
|
||||
- async
|
||||
- text
|
||||
- public
|
||||
---
|
||||
|
||||
## Application-text-async-logger
|
||||
|
||||
`ApplicationTextAsyncLogger` is the application-facing async logger alias for text-console output. It currently maps directly to `AsyncLogger[@bitlogger.FormattedConsoleSink]` and keeps the same async lifecycle and queue helper surface while preserving the concrete text sink shape.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type ApplicationTextAsyncLogger = AsyncLogger[@bitlogger.FormattedConsoleSink]
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `ApplicationTextAsyncLogger` - Application-facing name for the text-console async logger shape.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This alias does not introduce a new runtime type or wrapper layer.
|
||||
- It preserves the same async lifecycle helpers as other async logger aliases.
|
||||
- Because it is `AsyncLogger[@bitlogger.FormattedConsoleSink]`, the alias also keeps ordinary async logger composition and target behavior such as `with_target(...)`, `child(...)`, and per-call `log(..., target=...)` overrides.
|
||||
- In particular, `log(..., target=...)` can override the target for one call, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- Like the broader runtime-sink async alias, `with_context_fields(...)` and `bind(...)` preserve the visible `ApplicationTextAsyncLogger` shape because shared fields are stored directly on the async logger value instead of being modeled as a separate sink wrapper.
|
||||
- Because this is only an alias, methods that are async on `AsyncLogger[@bitlogger.FormattedConsoleSink]` remain async here as well.
|
||||
- The alias therefore keeps the same text-console-specific builder and lifecycle semantics already documented on `AsyncLogger[@bitlogger.FormattedConsoleSink]`, including the concrete sink shape plus the same close, queue, and failure-state behavior.
|
||||
- The application-facing type does not hide any async state or lifecycle helpers; queue/backlog/failure inspection remains directly available on this alias just as it is on the underlying `AsyncLogger[@bitlogger.FormattedConsoleSink]`.
|
||||
- In the current direct alias coverage, values built through `build_application_text_async_logger(...)` keep the same serialized state snapshot shape, formatter behavior, queue counters, lifecycle flags, and failure fields that the underlying text-console async logger exposes directly.
|
||||
- When the value is built through `build_application_text_async_logger(...)`, the direct async counters come from the outer async logger only; any optional sync queue configured on `LoggerConfig.queue` is not carried into this text-specific build path.
|
||||
- When the value is built through `build_application_text_async_logger(...)`, `logger.sink.kind` also does not decide the runtime sink shape. The builder still constructs `FormattedConsoleSink` from `logger.sink.text_formatter`, even if the config said `Console`, `JsonConsole`, or `File`.
|
||||
- When the value is built through `build_application_text_async_logger(...)`, `flush_policy()` still reports the configured async policy, but the text-specific build path keeps the default no-op async flush callback instead of wiring an explicit sink flush step.
|
||||
- The alias exists to give application code a clearer public name when it wants the concrete text-console sink shape explicitly.
|
||||
- `build_application_text_async_logger(...)` returns this alias.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need An App-level Name For Text-console Async Output
|
||||
|
||||
When application code wants a stable type name for a text-console async logger:
|
||||
```moonbit
|
||||
let logger : ApplicationTextAsyncLogger = build_application_text_async_logger(
|
||||
AsyncLoggerBuildConfig::new(logger=text_console(target="app.text.async")),
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the application alias keeps the same underlying async logger behavior while preserving the text sink shape explicitly.
|
||||
|
||||
#### When Pass A Text-console Async Logger Through App-level APIs
|
||||
|
||||
When caller code should know it is working with the text-console variant:
|
||||
```moonbit
|
||||
async fn start_text_async(logger : ApplicationTextAsyncLogger) -> Unit {
|
||||
logger.run()
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the app-facing alias communicates the concrete text-console async shape directly, while `run()` keeps its async calling contract.
|
||||
|
||||
And the same pending-count, state, and failure helpers remain directly available because no narrowing wrapper is added.
|
||||
|
||||
And the inherited async logger target rules stay the same: `log(..., target=...)` can override the target per call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need A One-call Target Override On The Text-console Alias
|
||||
|
||||
When app-level text-console async code should keep the same alias value but emit one record under a different target:
|
||||
```moonbit
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="app.text.async.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `app.text.async.audit` only for that one call.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the alias value's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Shared Context On The Text-console Async Alias
|
||||
|
||||
When app-level text-console async code should attach stable metadata to later queued records:
|
||||
```moonbit
|
||||
let contextual = logger.with_context_fields([@bitlogger.field("service", "billing")])
|
||||
```
|
||||
|
||||
In this example, the returned value still has the visible type `ApplicationTextAsyncLogger`.
|
||||
|
||||
And that shape preservation is intentional because async context binding updates stored logger metadata instead of changing the exposed sink type.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- Because this is only an alias, any async target limitations or runtime behavior still apply unchanged.
|
||||
|
||||
- If code does not need the concrete text-console sink shape, `ApplicationAsyncLogger` is the broader runtime-sink async alias.
|
||||
|
||||
- If the value came from `build_application_text_async_logger(...)`, carrying `logger.sink.kind=File` in the config still does not make this alias file-backed; that builder keeps the formatter-driven text-console path.
|
||||
|
||||
- If callers depend on the concrete formatter or direct text-console helper surface, they remain available on this alias because no wrapper layer narrows them away.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This alias is about naming and public intent, not a different async implementation.
|
||||
|
||||
2. Inherited `AsyncLogger` behavior stays unchanged on this alias, including target overrides on `log(...)` and derived target composition through `with_target(...)` and `child(...)`.
|
||||
|
||||
3. Use `build_application_text_async_logger(...)` when callers want the `FormattedConsoleSink`-backed async type explicitly.
|
||||
|
||||
4. Use `ApplicationAsyncLogger` when application code should keep the broader runtime-sink shape instead of the text-console-specific one.
|
||||
|
||||
5. Use `LibraryAsyncLogger[@bitlogger.FormattedConsoleSink]` instead when a library boundary should intentionally narrow the exposed async surface while still preserving the concrete text sink type.
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
name: async-flush-policy
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public flush policy alias used by AsyncLoggerConfig, async parser labels, and async worker flushing.
|
||||
key-word:
|
||||
- async
|
||||
- flush
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-flush-policy
|
||||
|
||||
`AsyncFlushPolicy` is the public enum that defines when an async logger should call its flush function. It is a direct alias to the async model enum used by `AsyncLoggerConfig`, worker execution, and async logger state reporting.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type AsyncFlushPolicy = @utils.AsyncFlushPolicy
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncFlushPolicy` - Public async flush enum with the variants `Never`, `Batch`, and `Shutdown`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a separate lifecycle wrapper.
|
||||
- `AsyncFlushPolicy::Never` skips explicit flush calls from the async worker.
|
||||
- `AsyncFlushPolicy::Batch` calls the configured flush function after each processed batch.
|
||||
- `AsyncFlushPolicy::Shutdown` calls the configured flush function once after the worker loop exits.
|
||||
- The current flush policy is also exposed through `AsyncLogger::flush_policy()` and included in `AsyncLoggerState`.
|
||||
- The canonical labels `Never`, `Batch`, and `Shutdown` are also the labels emitted by async config and logger-state serializers, so parsing and diagnostics share one public vocabulary.
|
||||
- Async config parsing accepts the canonical label `Never` and also the compatibility alias `None`, both mapping to the same public enum variant.
|
||||
- `Batch` flushing happens after the worker finishes one drained batch, not after every individual record write.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need Explicit Flush After Every Processed Batch
|
||||
|
||||
When buffered sinks should flush incrementally during worker execution:
|
||||
```moonbit
|
||||
let config = AsyncLoggerConfig::new(flush=AsyncFlushPolicy::Batch)
|
||||
```
|
||||
|
||||
In this example, each batch run triggers the provided flush callback.
|
||||
|
||||
#### When Need One Final Flush During Shutdown
|
||||
|
||||
When sink flushing should be deferred until the worker finishes:
|
||||
```moonbit
|
||||
let config = AsyncLoggerConfig::new(flush=AsyncFlushPolicy::Shutdown)
|
||||
```
|
||||
|
||||
In this example, flushing happens when the worker loop exits instead of after each batch.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If async config text uses unsupported flush policy text, async config parsing raises a failure.
|
||||
|
||||
- The parser error path for unsupported flush text is the same `Failure` surface used by the async config utilities.
|
||||
|
||||
- If a sink never needs explicit flushing, `Batch` or `Shutdown` can add unnecessary work without changing output.
|
||||
|
||||
- If the configured flush callback raises, the worker records failure state and stops instead of silently hiding the error.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This policy only affects the async logger path and only matters when the configured sink has a meaningful flush function.
|
||||
|
||||
2. `AsyncFlushPolicy::Never` is the default in `AsyncLoggerConfig::new(...)`.
|
||||
|
||||
3. Serialized config uses the canonical `Never` label even though the parser also accepts `None`.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-build-config-to-json
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Convert AsyncLoggerBuildConfig into a JSON value for exporting complete async logger build settings.
|
||||
update-time: 20260614
|
||||
description: Convert AsyncLoggerBuildConfig into a JSON value for exporting the full shared async build shape that can later feed either async builder path.
|
||||
key-word:
|
||||
- async
|
||||
- build
|
||||
@@ -38,7 +38,13 @@ Detailed rules explaining key parameters and behaviors
|
||||
- The output always includes `logger` and `async_config`.
|
||||
- Logger export is delegated to `@bitlogger.logger_config_to_json(...)`.
|
||||
- Async export is delegated to `async_logger_config_to_json(...)`.
|
||||
- Because both sections are always materialized, parsed defaults that were originally omitted in JSON input become explicit again in the exported build-config shape.
|
||||
- This helper is useful when generated setup should preserve both sink/logger behavior and async runtime behavior together.
|
||||
- The exported `logger` section keeps the full `LoggerConfig` shape, including fields that only matter on the full sync-first builder path such as the optional sync queue layer.
|
||||
- That means the JSON shape is broader than the consumption pattern of `build_async_text_logger(...)`, which only uses selected text-oriented logger fields when building the sink.
|
||||
- In particular, the exported `logger.sink.kind` remains whatever the config currently says, but a later `build_async_text_logger(...)` call still ignores that sink-kind branch and constructs `FormattedConsoleSink` from `logger.sink.text_formatter`.
|
||||
- The same exported object is also the shared handoff shape for the application and library facade routes after parse. `parse_async_logger_build_config_text(...)` can read this JSON back into `AsyncLoggerBuildConfig`, and that parsed value can then flow unchanged into `build_application_async_logger(...)`, `build_application_text_async_logger(...)`, `build_library_async_logger(...)`, or `build_library_async_text_logger(...)`.
|
||||
- Because of that, the exported structure is descriptive config data rather than a commitment to one public async type. The later builder or facade API still decides whether the runtime-sink line or the text-console line is taken.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -58,6 +64,12 @@ let payload = async_logger_build_config_to_json(
|
||||
|
||||
In this example, both layers of configuration are exported together.
|
||||
|
||||
And later consumers can still choose whether to rebuild through `build_async_logger(...)` or the narrower `build_async_text_logger(...)` path.
|
||||
|
||||
And that later text-specific builder choice still matters more than the serialized `logger.sink.kind` value, because only the formatter-backed text path is consumed there.
|
||||
|
||||
And the same exported object can just as well be parsed and then routed into the application or library facade builders when the next consumer wants a narrower public async type.
|
||||
|
||||
#### When Need Roundtrip-friendly Build Config Data
|
||||
|
||||
When generated build config should later be parsed again:
|
||||
@@ -74,3 +86,19 @@ e.g.:
|
||||
|
||||
- If callers want direct text output, they should use `stringify_async_logger_build_config(...)` instead.
|
||||
|
||||
- Exporting the full `logger` section does not imply that every async builder will later consume every logger field equally.
|
||||
|
||||
- Exporting `logger.sink.kind="file"` or `"console"` also does not force the later text-specific builder path to branch that way; only `build_async_logger(...)` follows sink kind when constructing the runtime sink.
|
||||
|
||||
- Choosing an application or library facade builder later does not change the meaning of the exported config by itself; those facade APIs inherit the same runtime-sink-versus-text-console split from the direct builder they delegate to.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when tools or tests need a structured JSON object instead of text.
|
||||
|
||||
2. Use `stringify_async_logger_build_config(...)` when the same build shape should be emitted as JSON text directly.
|
||||
|
||||
3. The resulting object round-trips through `parse_async_logger_build_config_text(...)`, even though different async builders later consume different parts of the embedded `LoggerConfig`.
|
||||
|
||||
4. After parsing, that same object can also feed the application or library facade builders; export preserves one shared build-config shape, not a direct-builder-only route.
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
name: async-logger-build-config-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public async build config alias combining the base logger config and async runtime config for both the general async builder path and the specialized text-console builder path.
|
||||
key-word:
|
||||
- async
|
||||
- build
|
||||
- config
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-build-config-type
|
||||
|
||||
`AsyncLoggerBuildConfig` is the public config object that combines the base synchronous `LoggerConfig` with the async runtime `AsyncLoggerConfig`. It is a direct alias to the build-config model used by async builder APIs, parsers, and serializers, even though the available builders consume different parts of the embedded sync config.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type AsyncLoggerBuildConfig = @utils.AsyncLoggerBuildConfig
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerBuildConfig` - Public async build config object containing `logger` and `async_config`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a built logger instance.
|
||||
- The current fields are `logger : LoggerConfig` and `async_config : AsyncLoggerConfig`.
|
||||
- The public `src-async` surface forwards this alias directly from `@utils.AsyncLoggerBuildConfig`, so constructor, parser, export, and stringify helpers all operate on one shared underlying build-config model.
|
||||
- `AsyncLoggerBuildConfig::new(...)` constructs this type as the main handoff object for async build flows.
|
||||
- `build_async_logger(...)`, `build_async_text_logger(...)`, `parse_async_logger_build_config_text(...)`, `async_logger_build_config_to_json(...)`, and `stringify_async_logger_build_config(...)` all consume or produce this same public shape.
|
||||
- The same typed object also feeds the application and library facade builders. `build_application_async_logger(...)`, `build_application_text_async_logger(...)`, `build_library_async_logger(...)`, and `build_library_async_text_logger(...)` all accept this exact config type and then delegate to one of the two direct builder lines.
|
||||
- The parse-and-build facade helpers use the same model as well. `parse_and_build_application_async_logger(...)` and `parse_and_build_library_async_logger(...)` first parse JSON into this build-config shape and then forward into their respective facade builders.
|
||||
- `build_async_logger(...)` consumes the full sync build path by calling `build_logger(config.logger)` first, so `LoggerConfig.sink`, `LoggerConfig.queue`, and the resulting runtime sink behavior all participate before the async layer is added.
|
||||
- `build_async_text_logger(...)` is narrower: it builds a text console sink directly from `config.logger.sink.text_formatter` and the top-level `min_level`, `target`, and `timestamp` fields, without applying `LoggerConfig.queue`.
|
||||
- On that text-specific path, `config.logger.sink.kind` also does not decide the runtime sink shape. `build_async_text_logger(...)` still constructs `FormattedConsoleSink` from `config.logger.sink.text_formatter` even if the config says `Console`, `JsonConsole`, or `File`.
|
||||
- In practice, the builder function you choose is what decides how the embedded `LoggerConfig` is interpreted. The runtime-sink line (`build_async_logger(...)` and the application/library facades layered on it) preserves the full sync build path, while the text-console line (`build_async_text_logger(...)` and the facades layered on it) ignores the optional sync queue and does not branch on `logger.sink.kind`.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need One Typed Object For Full Async Logger Setup
|
||||
|
||||
When sync sink setup and async runtime policy should move together through application boot code:
|
||||
```moonbit
|
||||
let config : AsyncLoggerBuildConfig = AsyncLoggerBuildConfig::new(
|
||||
logger=@bitlogger.LoggerConfig::new(target="svc"),
|
||||
async_config=AsyncLoggerConfig::new(max_pending=64),
|
||||
)
|
||||
```
|
||||
|
||||
In this example, both layers of logger setup are kept in one typed value.
|
||||
|
||||
And downstream code can still choose between the full sync-first builder path and the narrower text-console builder path.
|
||||
|
||||
And if downstream code chooses `build_async_text_logger(...)`, that builder choice still matters more than `logger.sink.kind` because only the formatter-backed text path is consumed there.
|
||||
|
||||
And the same typed object can be handed unchanged to `build_application_async_logger(...)`, `build_application_text_async_logger(...)`, `build_library_async_logger(...)`, or `build_library_async_text_logger(...)` when the caller wants a different public facade over the same underlying build decision.
|
||||
|
||||
#### When Need To Export Or Inspect The Full Build Shape
|
||||
|
||||
When application code should inspect the combined async build configuration before constructing the logger:
|
||||
```moonbit
|
||||
let config = AsyncLoggerBuildConfig::new(async_config=AsyncLoggerConfig::new(max_batch=4))
|
||||
println(stringify_async_logger_build_config(config, pretty=true))
|
||||
```
|
||||
|
||||
In this example, the same public config object supports both review and later build steps.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `AsyncLoggerBuildConfig` itself does not have a runtime failure mode.
|
||||
|
||||
- If only async runtime policy is needed and the base sync logger config is irrelevant, this type may be broader than necessary and `AsyncLoggerConfig` is the smaller fit.
|
||||
|
||||
- If callers expect every `LoggerConfig` field to affect every async builder in the same way, that assumption is too broad: the text-specific builder intentionally ignores the optional sync queue layer.
|
||||
|
||||
- In particular, carrying `logger.sink.kind=File` inside this config type does not force the later text-specific builder path to create a file-backed async logger; only `build_async_logger(...)` branches on sink kind.
|
||||
|
||||
- Likewise, choosing an application or library facade builder does not change these config semantics by itself. Those facade APIs inherit the same runtime-sink-versus-text-console split from the direct builder they delegate to.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `AsyncLoggerBuildConfig::new(...)` when one object should carry both sync and async logger setup.
|
||||
|
||||
2. Use `parse_async_logger_build_config_text(...)` when the same shape should come from JSON text instead of handwritten code.
|
||||
|
||||
3. Pick `build_async_logger(...)` when the full synchronous config path, including `LoggerConfig.queue`, should be preserved before async wrapping.
|
||||
|
||||
4. Pick `build_async_text_logger(...)` when the goal is specifically a concrete text console sink and only the selected text-oriented `LoggerConfig` fields should apply.
|
||||
|
||||
5. Pick the application or library facade builders when the same config should drive one of those narrower public surfaces; the chosen facade changes the exposed type, but the direct builder line underneath still determines whether queue and sink-kind settings are preserved or ignored.
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: async-logger-build-config
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Create the combined sync-and-async build config used by async logger builder APIs, whether callers later choose the full sync-first builder path or the specialized text-console builder path.
|
||||
key-word:
|
||||
- async
|
||||
- build
|
||||
- config
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-build-config
|
||||
|
||||
Create an `AsyncLoggerBuildConfig` value that combines the base synchronous `LoggerConfig` with the async runtime `AsyncLoggerConfig`. This is the constructor used when async builder APIs should receive one typed object carrying both layers of setup, even though different builders later consume different parts of the embedded sync config.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub fn AsyncLoggerBuildConfig::new(
|
||||
logger~ : @bitlogger.LoggerConfig = @bitlogger.default_logger_config(),
|
||||
async_config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||
) -> AsyncLoggerBuildConfig {
|
||||
```
|
||||
|
||||
#### input
|
||||
|
||||
- `logger : LoggerConfig` - Base synchronous logger config describing the sink, level, target, related sync logger settings, and any optional synchronous queue wrapper.
|
||||
- `async_config : AsyncLoggerConfig` - Async runtime config describing queue, batching, linger, and flush behavior.
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerBuildConfig` - Combined build config used by async logger build and parse helpers.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Omitting `logger` uses `default_logger_config()`.
|
||||
- Omitting `async_config` uses `AsyncLoggerConfig::new()`.
|
||||
- The constructor simply packages both config objects into one public build shape.
|
||||
- The constructor does not normalize or reinterpret either embedded config beyond those defaults; any normalization has already happened inside the `LoggerConfig` or `AsyncLoggerConfig` values passed in.
|
||||
- When passed to `build_async_logger(...)`, the `logger` portion is built first through the normal synchronous config path before the outer async queue layer is applied.
|
||||
- When passed to `build_async_text_logger(...)`, the same `logger` portion is consumed more narrowly: `text_formatter`, `min_level`, `target`, and `timestamp` are used directly to build a text console sink, while `LoggerConfig.queue` is not applied.
|
||||
- On that text-specific path, `logger.sink.kind` also does not decide the runtime sink shape. `build_async_text_logger(...)` still constructs `FormattedConsoleSink` from `logger.sink.text_formatter` even if the config says `Console`, `JsonConsole`, or `File`.
|
||||
- This helper is the main code-side counterpart to `parse_async_logger_build_config_text(...)`.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need One Typed Object For Async Builder Input
|
||||
|
||||
When sync sink setup and async runtime policy should travel together through build code:
|
||||
```moonbit
|
||||
let config = AsyncLoggerBuildConfig::new(
|
||||
logger=@bitlogger.LoggerConfig::new(target="svc.async"),
|
||||
async_config=AsyncLoggerConfig::new(max_pending=64, max_batch=8),
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the builder input keeps both configuration layers in one typed value.
|
||||
|
||||
And later code can still decide whether that shared config should flow into the full sync-first builder or the narrower text-console builder.
|
||||
|
||||
And if later code chooses `build_async_text_logger(...)`, that builder choice still matters more than `logger.sink.kind` because only the formatter-backed text path is consumed there.
|
||||
|
||||
#### When Need Defaulted Async Build Settings
|
||||
|
||||
When code only wants the standard combined config shape with few overrides:
|
||||
```moonbit
|
||||
let config = AsyncLoggerBuildConfig::new(async_config=AsyncLoggerConfig::new(max_batch=4))
|
||||
```
|
||||
|
||||
In this example, the base sync logger config falls back to its default value automatically.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- This constructor itself does not have a normal failure mode; it only packages configuration values.
|
||||
|
||||
- If callers only need async runtime policy and not the full builder input shape, `AsyncLoggerConfig::new(...)` is the smaller API.
|
||||
|
||||
- If callers expect every field inside `LoggerConfig` to affect every async builder equally, that assumption is too broad: `build_async_text_logger(...)` intentionally skips the optional sync queue layer.
|
||||
|
||||
- In particular, carrying `logger.sink.kind=File` inside this config does not force the later text-specific builder path to create a file-backed async logger; only `build_async_logger(...)` branches on sink kind.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when async builder APIs should receive one combined config object.
|
||||
|
||||
2. Pair it with `build_async_logger(...)`, `build_async_text_logger(...)`, or `parse_async_logger_build_config_text(...)` depending on whether the source is code or JSON text.
|
||||
|
||||
3. Prefer `build_async_logger(...)` after constructing this value when configured sync sink behavior, including `LoggerConfig.queue`, should be preserved before async wrapping.
|
||||
|
||||
4. Prefer `build_async_text_logger(...)` after constructing this value when the goal is specifically config-driven text console output with a concrete `FormattedConsoleSink`.
|
||||
@@ -28,16 +28,18 @@ pub fn[S] AsyncLogger::child(self : AsyncLogger[S], target : String) -> AsyncLog
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLogger[S]` - A new async logger whose default target is the composed child path.
|
||||
- `AsyncLogger[S]` - A new async logger value whose default target is the composed child path.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The returned logger is derived from `self`; the original async logger value is not mutated.
|
||||
- If the parent target is empty, the child target becomes the full target.
|
||||
- If the child target is empty, the parent target is preserved.
|
||||
- If both are non-empty, they are joined with `.`.
|
||||
- Queue settings, sink wiring, and runtime behavior are preserved in the returned logger.
|
||||
- Only the stored target changes. Queue settings, sink wiring, flush policy, level gating, and lifecycle state remain shared with the same underlying async logger setup.
|
||||
- In the current direct async coverage, `timestamp` is also preserved on the derived child logger while the source logger keeps its previous parent target.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -53,6 +55,8 @@ let worker = logger.child("worker")
|
||||
|
||||
In this example, `worker` emits under `service.worker` while keeping the same async queue behavior.
|
||||
|
||||
And `logger` still keeps its original stored target, because `child(...)` returns a derived async logger value instead of mutating the parent.
|
||||
|
||||
#### When Build Deep Async Scopes Step By Step
|
||||
|
||||
When deeper target composition should remain readable:
|
||||
@@ -76,3 +80,7 @@ e.g.:
|
||||
1. This is the preferred API for hierarchical async logger naming.
|
||||
|
||||
2. Composition changes the target only and does not rebuild the queue or sink.
|
||||
|
||||
3. State helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, and `has_failed()` still operate on the same async logger state after derivation.
|
||||
|
||||
4. Use `child("")` when code should keep the current target while still following a target-composition code path.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-close
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Close the async logger queue and optionally clear pending records immediately.
|
||||
update-time: 20260614
|
||||
description: Close the async logger queue immediately and optionally convert current pending backlog into dropped records before queue closure.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -38,6 +38,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `clear=false` closes the queue without explicitly abandoning pending records in the helper itself.
|
||||
- `clear=true` counts pending records as dropped and resets `pending_count` to `0` before closing the queue.
|
||||
- This helper does not itself wait for the worker to finish.
|
||||
- `close(...)` also does not change `has_failed()` or `last_error()`; it is a closure primitive, not a failure reset API.
|
||||
- Because this is a low-level close primitive, it does not first run `wait_idle()` or apply the runtime-dependent fallback logic used by `shutdown()`.
|
||||
- After closure, later log attempts do not add new pending or dropped counts, but backend behavior can still differ before the closed queue rejects the record.
|
||||
- In the current direct coverage, compatibility runtimes short-circuit before patch-path work on late log attempts, while native-worker runtimes may still build and patch the record before the closed queue rejects it.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -66,6 +70,10 @@ In this example, queued backlog is counted as dropped instead of waiting for fur
|
||||
e.g.:
|
||||
- If `clear=true`, pending records are intentionally discarded and contribute to `dropped_count()`.
|
||||
|
||||
- If `clear=false`, pending records may still exist after closure until worker drain or later cleanup resolves them.
|
||||
|
||||
- If callers perform late log attempts after closure, backlog counters still stay unchanged, but patch-path side effects are runtime-dependent and should not be treated as a portable post-close contract.
|
||||
|
||||
- If callers need graceful waiting for drain completion, `shutdown()` is usually the better API.
|
||||
|
||||
### Notes
|
||||
@@ -73,3 +81,5 @@ e.g.:
|
||||
1. This is a low-level lifecycle helper; prefer `shutdown()` for normal graceful teardown.
|
||||
|
||||
2. Use `clear=true` only when backlog loss is an acceptable shutdown tradeoff.
|
||||
|
||||
3. Pair it with `pending_count()`, `dropped_count()`, or `state()` when you need to observe what happened to existing backlog after closure.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-config-to-json
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Convert AsyncLoggerConfig into a JSON value for export, persistence, or generated async config output.
|
||||
update-time: 20260614
|
||||
description: Convert AsyncLoggerConfig into a JSON value for export, persistence, or generated async config output using the stable serialized policy labels.
|
||||
key-word:
|
||||
- async
|
||||
- config
|
||||
@@ -36,6 +36,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
- The output includes `max_pending`, `max_batch`, `linger_ms`, `overflow`, and `flush`.
|
||||
- Policy fields are serialized using the stable labels accepted by the config parser.
|
||||
- This helper exports effective typed config after constructor normalization has already happened.
|
||||
- If `max_pending` is negative in the config object, the exported JSON preserves that negative value because runtime queue clamping happens later, not during serialization.
|
||||
- The JSON shape matches the `async_config` section used by async build config parsing.
|
||||
|
||||
### How to Use
|
||||
@@ -67,5 +68,13 @@ In this example, the exported JSON stays aligned with parser expectations.
|
||||
e.g.:
|
||||
- If `max_batch` or `linger_ms` were normalized during construction, the exported JSON reflects the normalized values rather than the original invalid inputs.
|
||||
|
||||
- If callers need to understand runtime queue behavior for negative `max_pending`, they should document that separately because serialization preserves the config value rather than the later queue-kind clamp.
|
||||
|
||||
- If callers want direct text output instead of a JSON value, they should use `stringify_async_logger_config(...)` instead.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Serialized policy labels round-trip through `parse_async_logger_config_text(...)`.
|
||||
|
||||
2. The serializer emits canonical labels like `DropNewest` and `Never`, even though the parser also accepts compatibility aliases such as `DropLatest` and `None`.
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: async-logger-config-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public async logger config alias used for async queue interpretation, batching, linger, and flush settings.
|
||||
key-word:
|
||||
- async
|
||||
- config
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-config-type
|
||||
|
||||
`AsyncLoggerConfig` is the public config object used to describe async queue capacity, overflow behavior, batching, linger timing, and flush policy. It is a direct alias to the async config model used by `async_logger(...)`, config parsers, and async config serializers.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type AsyncLoggerConfig = @utils.AsyncLoggerConfig
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerConfig` - Public async config object containing `max_pending`, `overflow`, `max_batch`, `linger_ms`, and `flush`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a runtime logger handle.
|
||||
- The current fields are `max_pending : Int`, `overflow : AsyncOverflowPolicy`, `max_batch : Int`, `linger_ms : Int`, and `flush : AsyncFlushPolicy`.
|
||||
- The public `src-async` surface forwards this alias directly from `@utils.AsyncLoggerConfig`, so constructor, parser, export, and stringify helpers all operate on one shared underlying config model.
|
||||
- `AsyncLoggerConfig::new(...)` normalizes `max_batch` and `linger_ms`, but it preserves the provided `max_pending` value.
|
||||
- Runtime queue creation later interprets negative `max_pending` as `0` when choosing the internal queue kind.
|
||||
- `parse_async_logger_config_text(...)`, `async_logger_config_to_json(...)`, and `stringify_async_logger_config(...)` all operate on this same public config shape.
|
||||
- The parser accepts the stable serialized labels such as `DropNewest` and `Never`, plus compatibility aliases such as `DropLatest` and `None`.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Typed Async Runtime Policy Value
|
||||
|
||||
When async queue and flush behavior should be passed around as structured config:
|
||||
```moonbit
|
||||
let config : AsyncLoggerConfig = AsyncLoggerConfig::new(
|
||||
max_pending=64,
|
||||
overflow=AsyncOverflowPolicy::DropOldest,
|
||||
)
|
||||
```
|
||||
|
||||
In this example, async policy remains a typed object instead of immediately becoming JSON text or a logger instance.
|
||||
|
||||
#### When Need To Inspect The Config Before Building
|
||||
|
||||
When one layer should read or adjust async policy before logger construction:
|
||||
```moonbit
|
||||
let config = AsyncLoggerConfig::new(max_batch=4, linger_ms=20)
|
||||
println(stringify_async_logger_config(config, pretty=true))
|
||||
```
|
||||
|
||||
In this example, the same public config object supports both inspection and later build steps.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `AsyncLoggerConfig` itself does not have a runtime failure mode.
|
||||
|
||||
- Constructor normalization still applies when the value is created through `AsyncLoggerConfig::new(...)`, so very small batch sizes and negative linger values may be adjusted before later serialization or use.
|
||||
|
||||
- Negative `max_pending` is not rewritten inside the config object itself; it is only clamped later when the async queue kind is derived at runtime.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `AsyncLoggerConfig::new(...)` when you need a value of this type in code.
|
||||
|
||||
2. Use `AsyncLoggerBuildConfig` when the async config should travel together with the base synchronous `LoggerConfig`.
|
||||
|
||||
3. Use `parse_async_logger_config_text(...)` when the same shape should come from JSON text, including accepted aliases like `DropLatest` and `None`.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-config
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Create the queue, batching, linger, and flush policy config used by async loggers.
|
||||
update-time: 20260614
|
||||
description: Create the async queue, batching, linger, and flush policy config used by async loggers.
|
||||
key-word:
|
||||
- async
|
||||
- config
|
||||
@@ -29,7 +29,7 @@ pub fn AsyncLoggerConfig::new(
|
||||
|
||||
#### input
|
||||
|
||||
- `max_pending : Int` - Maximum queued records.
|
||||
- `max_pending : Int` - Requested maximum queued records before overflow policy matters; negative values are preserved in the config object and later treated as `0` by runtime queue creation.
|
||||
- `overflow : AsyncOverflowPolicy` - Queue overflow strategy.
|
||||
- `max_batch : Int` - Maximum records drained per batch.
|
||||
- `linger_ms : Int` - Optional wait window for batch accumulation.
|
||||
@@ -45,6 +45,8 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `max_batch <= 1` is normalized to `1`.
|
||||
- `linger_ms < 0` is normalized to `0`.
|
||||
- `max_pending` is stored as provided by the constructor.
|
||||
- When the async logger runtime later builds its internal queue, negative `max_pending` is interpreted as `0`.
|
||||
- `overflow` and `flush` define the most important queue/runtime behavior tradeoffs.
|
||||
- This type is used directly by `async_logger(...)` and embedded in `AsyncLoggerBuildConfig`.
|
||||
|
||||
@@ -79,12 +81,14 @@ In this example, the config becomes a stable JSON payload.
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If `max_batch` is set to `0` or below, runtime config normalizes it to `1`.
|
||||
- If `max_batch` is set to `0` or below, constructor normalization changes it to `1`.
|
||||
|
||||
- If `linger_ms` is negative, it is normalized to `0`.
|
||||
- If `linger_ms` is negative, constructor normalization changes it to `0`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This type controls async runtime behavior, not synchronous queue wrapping.
|
||||
|
||||
2. Prefer explicit values for production services so overflow and flush semantics are visible.
|
||||
|
||||
3. If queue limit semantics for negative values matter, document that behavior explicitly in calling code because the config object preserves the negative value while the runtime queue later clamps it to `0`.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-debug
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Enqueue a debug-level record through the async logger using the built-in severity shortcut.
|
||||
update-time: 20260614
|
||||
description: Enqueue a debug-level record through the async logger using the built-in severity shortcut and the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -39,8 +39,9 @@ pub async fn[S] AsyncLogger::debug(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This helper delegates to `log(Level::Debug, ...)`.
|
||||
- This helper delegates to `log(Level::Debug, ..., fields=fields)`.
|
||||
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
|
||||
- This helper does not accept a per-call target override. It uses the logger's stored target unless the logger was derived earlier with `with_target(...)` or `child(...)`.
|
||||
- Debug records are useful for development and targeted diagnostics.
|
||||
- Use this helper when a named debug call is clearer than a raw `log(...)` call.
|
||||
|
||||
@@ -52,7 +53,7 @@ Here are some specific examples provided.
|
||||
|
||||
When intermediate async flow details should be visible during debugging:
|
||||
```moonbit
|
||||
await logger.debug("loaded worker config")
|
||||
logger.debug("loaded worker config")
|
||||
```
|
||||
|
||||
In this example, the call site communicates its intended diagnostic level directly.
|
||||
@@ -61,7 +62,7 @@ In this example, the call site communicates its intended diagnostic level direct
|
||||
|
||||
When a debug event should include extra fields:
|
||||
```moonbit
|
||||
await logger.debug(
|
||||
logger.debug(
|
||||
"dispatch start",
|
||||
fields=[@bitlogger.field("job_id", "42")],
|
||||
)
|
||||
@@ -80,4 +81,4 @@ e.g.:
|
||||
|
||||
1. Prefer this helper when the event is semantically debug-level.
|
||||
|
||||
2. Use `log(...)` when the level must be chosen dynamically.
|
||||
2. Use `log(...)` when the level must be chosen dynamically or one call needs a target override.
|
||||
|
||||
@@ -35,6 +35,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The counter increases when overflow policy discards records.
|
||||
- The counter can also increase when `close(clear=true)` or `shutdown(clear=true)` abandons queued records.
|
||||
- It can also increase when shutdown fallback logic converts remaining pending records into dropped records during a clear-close path.
|
||||
- After a worker failure short-circuits `wait_idle()`, that shutdown-fallback increase is runtime-dependent in the current implementation: native-worker shutdown can convert leftover pending records into additional dropped records, while compatibility shutdown can leave that closed-queue remainder visible in `pending_count()` instead.
|
||||
- That also means `dropped_count()` can still stay unchanged even after `is_closed=true` and retained failure state on compatibility-style shutdown paths, because closure there does not necessarily convert the leftover failed backlog into dropped records.
|
||||
- Later log attempts against an already closed queue do not add to this counter by themselves.
|
||||
- This is a cumulative counter for the lifetime of the logger value.
|
||||
- Use this helper when you need a focused loss metric rather than a full `state()` snapshot.
|
||||
|
||||
@@ -70,6 +74,8 @@ e.g.:
|
||||
|
||||
- If callers need to know why records were lost, they must interpret this metric together with overflow policy and shutdown behavior.
|
||||
|
||||
- If `wait_idle()` returned early because the worker failed, `dropped_count()` may still stay unchanged on compatibility shutdown paths even though one leftover closed-queue item remains visible in `pending_count()`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This helper reports record loss only; it does not explain the full logger state.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-error
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Enqueue an error-level record through the async logger using the highest built-in severity shortcut.
|
||||
update-time: 20260614
|
||||
description: Enqueue an error-level record through the async logger using the highest built-in severity shortcut and the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -39,8 +39,9 @@ pub async fn[S] AsyncLogger::error(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This helper delegates to `log(Level::Error, ...)`.
|
||||
- The record is still subject to patching, filtering, and overflow policy.
|
||||
- This helper delegates to `log(Level::Error, ..., fields=fields)`.
|
||||
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
|
||||
- This helper does not accept a per-call target override. It uses the logger's stored target unless the logger was derived earlier with `with_target(...)` or `child(...)`.
|
||||
- Error records represent the highest built-in severity in this logger API.
|
||||
- Use this helper when a named error call is clearer than a raw `log(...)` call.
|
||||
|
||||
@@ -52,7 +53,7 @@ Here are some specific examples provided.
|
||||
|
||||
When an operation should emit a high-severity failure event:
|
||||
```moonbit
|
||||
await logger.error("worker execution failed")
|
||||
logger.error("worker execution failed")
|
||||
```
|
||||
|
||||
In this example, failure intent is explicit at the call site.
|
||||
@@ -61,7 +62,7 @@ In this example, failure intent is explicit at the call site.
|
||||
|
||||
When an error event should include diagnostic fields:
|
||||
```moonbit
|
||||
await logger.error(
|
||||
logger.error(
|
||||
"dispatch failed",
|
||||
fields=[@bitlogger.field("job_id", "42")],
|
||||
)
|
||||
@@ -69,6 +70,10 @@ await logger.error(
|
||||
|
||||
In this example, the error record carries structured context without falling back to the generic `log(...)` form.
|
||||
|
||||
And any shared context already carried by the logger still participates ahead of these per-call fields when the record is built.
|
||||
|
||||
The write still uses the logger's stored target because this shortcut does not take a one-off `target=` override.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -80,4 +85,6 @@ e.g.:
|
||||
|
||||
1. Use this helper for high-severity async application failures.
|
||||
|
||||
2. Emitting an error record is separate from the logger worker itself entering failure state.
|
||||
2. Use `log(...)` instead when an error call needs a one-off target override.
|
||||
|
||||
3. Emitting an error record is separate from the logger worker itself entering failure state.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-flush-policy
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read the async logger flush policy currently governing batch and shutdown flushing behavior.
|
||||
update-time: 20260614
|
||||
description: Read the async logger flush policy currently governing batch-end and shutdown-end flushing behavior.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -34,9 +34,11 @@ pub fn[S] AsyncLogger::flush_policy(self : AsyncLogger[S]) -> AsyncFlushPolicy {
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The returned value reflects the policy captured when the async logger was created.
|
||||
- `Batch` causes explicit flush calls after worker batch processing.
|
||||
- `Shutdown` causes explicit flush calls at worker shutdown.
|
||||
- `Never` leaves flushing entirely to sink behavior or external control.
|
||||
- `Batch` means the worker invokes the stored async flush callback after each completed drained batch, not after every individual record write.
|
||||
- `Shutdown` means the worker invokes the stored async flush callback once after the worker loop exits.
|
||||
- `Never` leaves that explicit callback path unused and relies entirely on sink behavior or external control.
|
||||
- This helper reports callback timing policy, not a guarantee that a particular sink type has a meaningful built-in flush effect on every constructor path.
|
||||
- In particular, text-specific async builder paths keep the default no-op flush callback even when the visible policy is `Batch` or `Shutdown`, so the reported policy can describe when the callback would run without implying extra sink work actually happens on that path.
|
||||
|
||||
### How to Use
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-has-failed
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read whether the async logger worker has encountered a failure during queue drain.
|
||||
update-time: 20260614
|
||||
description: Read whether the async logger worker has recorded a runtime failure after run() startup reset and drain execution.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -34,7 +34,10 @@ pub fn[S] AsyncLogger::has_failed(self : AsyncLogger[S]) -> Bool {}
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `run()` clears previous failure state at startup.
|
||||
- `run()` also clears the stored `last_error()` string at startup before drain work begins.
|
||||
- If the worker loop raises an error, the logger records that failure and exposes it through this flag.
|
||||
- Once set by a failed run, the flag stays `true` until a later `run()` invocation actually starts and resets it.
|
||||
- Failure-driven shutdown does not clear this flag by itself, so `has_failed()` can remain `true` even after the logger is already closed.
|
||||
- This helper is intentionally compact and should usually be paired with `last_error()` for details.
|
||||
- Failure state is about runtime drain execution, not whether records were dropped due to overflow policy.
|
||||
|
||||
@@ -67,10 +70,19 @@ In this example, the helper exposes a simple pass-fail runtime indicator.
|
||||
e.g.:
|
||||
- If `has_failed()` is `false`, queue pressure or dropped records may still exist for non-failure reasons.
|
||||
|
||||
- If `has_failed()` becomes `true`, `wait_idle()` may stop early while pending records still remain until a later close or clear path handles them.
|
||||
- In the current regression coverage, that later handling can be an explicit `close(clear=true)` that resets pending backlog immediately or a runtime-dependent `shutdown(...)` path that either clears pending into dropped records or leaves the closed-queue remainder visible.
|
||||
|
||||
- If `has_failed()` is still `true` after shutdown, that does not by itself mean cleanup failed; the logger may already be `is_closed=true` while the remaining pending-versus-dropped outcome still reflects the active runtime's shutdown path.
|
||||
|
||||
- If `has_failed()` is `true`, callers should inspect `last_error()` or `state()` for more context.
|
||||
|
||||
- `close()` or `shutdown()` do not clear this flag by themselves; only a later `run()` that has already started resets it.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This helper reports worker failure, not general queue stress.
|
||||
|
||||
2. Pair it with `last_error()` when you need actionable detail.
|
||||
|
||||
3. Pair it with `is_running()` or `state()` when you also need to know whether the worker has already exited and whether backlog remains.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-info
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Enqueue an info-level record through the async logger using the most common built-in severity shortcut.
|
||||
update-time: 20260614
|
||||
description: Enqueue an info-level record through the async logger using the most common built-in severity shortcut and the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -39,8 +39,9 @@ pub async fn[S] AsyncLogger::info(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This helper delegates to `log(Level::Info, ...)`.
|
||||
- This helper delegates to `log(Level::Info, ..., fields=fields)`.
|
||||
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
|
||||
- This helper does not accept a per-call target override. It uses the logger's stored target unless the logger was derived earlier with `with_target(...)` or `child(...)`.
|
||||
- Info is often the default operational logging level for async application events.
|
||||
- Use this helper when explicit info intent is clearer than a raw `log(...)` call.
|
||||
|
||||
@@ -52,7 +53,7 @@ Here are some specific examples provided.
|
||||
|
||||
When async code should report routine progress or lifecycle events:
|
||||
```moonbit
|
||||
await logger.info("worker started")
|
||||
logger.info("worker started")
|
||||
```
|
||||
|
||||
In this example, the event is expressed at the most common operational logging level.
|
||||
@@ -61,7 +62,7 @@ In this example, the event is expressed at the most common operational logging l
|
||||
|
||||
When an info event should include stable structured detail:
|
||||
```moonbit
|
||||
await logger.info(
|
||||
logger.info(
|
||||
"job queued",
|
||||
fields=[@bitlogger.field("queue", "sync")],
|
||||
)
|
||||
@@ -69,6 +70,10 @@ await logger.info(
|
||||
|
||||
In this example, the record remains concise while still carrying useful metadata.
|
||||
|
||||
And any shared context already carried by the logger still participates ahead of these per-call fields when the record is built.
|
||||
|
||||
The write still uses the logger's stored target because this shortcut does not take a one-off `target=` override.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -80,4 +85,4 @@ e.g.:
|
||||
|
||||
1. This is often the most common convenience method for normal async application events.
|
||||
|
||||
2. Use `log(...)` when the call site needs a dynamic level or target override.
|
||||
2. Use `log(...)` when the call site needs a dynamic level or a one-off target override.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-is-closed
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read whether the async logger has been closed and should no longer accept normal new queue traffic.
|
||||
update-time: 20260614
|
||||
description: Read whether the async logger has entered closed lifecycle state and should no longer be treated as a normal active enqueue target.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -36,7 +36,11 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `close(...)` sets the closed state immediately.
|
||||
- `shutdown(...)` also results in a closed logger by the end of its lifecycle flow.
|
||||
- A closed logger should no longer be treated as a normal active enqueue target.
|
||||
- This helper is only a direct read of the current `is_closed` ref; it does not wait for drain completion or clear any other state.
|
||||
- This helper reflects lifecycle state only and does not indicate whether the worker is still draining.
|
||||
- `is_closed()` becoming `true` does not imply the logger reached a clean success state. Failure flags, retained `last_error()`, and remaining backlog-related counters can still reflect the earlier worker outcome.
|
||||
- After shutdown on a worker-failure path, `is_closed()` can therefore be `true` while backlog cleanup remains runtime-dependent: native-worker runtimes can convert leftover pending records into dropped ones, while compatibility runtimes can still report the remaining queue entries as pending.
|
||||
- Exact post-close logging behavior is runtime-dependent: compatibility runtimes can short-circuit before patch and enqueue work, while native-worker runtimes may still build and patch a record before the closed queue rejects it, so `is_closed()` should be read as a lifecycle signal rather than a full enqueue-policy contract.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -70,8 +74,16 @@ e.g.:
|
||||
|
||||
- If callers need to know whether the worker is still active, they should also inspect `is_running()`.
|
||||
|
||||
- If callers need to know whether closure also prevented later log attempts on the current backend, they must interpret this together with the active runtime behavior rather than this flag alone.
|
||||
|
||||
- Closing a logger does not by itself reset `has_failed()` or `last_error()`.
|
||||
|
||||
- A closed logger can still report leftover `pending_count()` or `dropped_count()` values from the shutdown path, so `is_closed()` alone is not enough to infer whether backlog was fully drained or explicitly abandoned.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Closed state and running state are related but not identical.
|
||||
|
||||
2. Use this helper when lifecycle control matters more than queue counters.
|
||||
|
||||
3. Pair it with `pending_count()`, `is_running()`, or `state()` when you need to understand what closure means for remaining backlog on a live logger instance.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-is-running
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read whether the async logger worker is currently running and draining the queue.
|
||||
update-time: 20260614
|
||||
description: Read whether the async logger worker loop is currently running, regardless of queue backlog or recorded failure state.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -36,7 +36,11 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `run()` sets the running state while the worker loop is active.
|
||||
- The flag is cleared when the worker exits normally or after failure handling finishes.
|
||||
- A logger may be closed while still running briefly during final drain or shutdown processing.
|
||||
- After a worker failure, the logger can already be `is_running=false` while still retaining `has_failed=true`, the recorded `last_error()`, and runtime-dependent leftover backlog or dropped-count cleanup.
|
||||
- This helper is only a direct read of the current `is_running` ref; it does not wait, synchronize, or infer why the value is what it is.
|
||||
- This helper focuses on worker activity rather than queue size or failure details.
|
||||
- `is_running()` can be `false` even when `pending_count()` is still nonzero, for example if the worker was never started or if it exited after a recorded failure.
|
||||
- A later `run()` attempt can flip `is_running()` back to `true` before that retained failure/backlog state has been fully drained, because the restarted worker clears stale failure state only once the new run has actually started.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -67,10 +71,18 @@ In this example, callers watch the worker lifecycle directly.
|
||||
e.g.:
|
||||
- If `is_running()` is `false`, pending records may still exist if the worker was never started or has already failed.
|
||||
|
||||
- If `is_running()` is `false`, the logger may also already be closed while still retaining the previous failure record and a runtime-dependent pending-versus-dropped cleanup result from shutdown.
|
||||
|
||||
- If callers need a one-shot lifecycle flow, `shutdown()` is usually better than manual polling.
|
||||
|
||||
- If `is_running()` is `true`, that still does not guarantee healthy drain progress; callers may need `has_failed()` or `state()` for failure context.
|
||||
|
||||
- Under concurrent activity, the returned value may change immediately after it is read.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper for worker activity checks, not as a complete health signal.
|
||||
|
||||
2. Pair it with `has_failed()` or `state()` when diagnosing stalled pipelines.
|
||||
|
||||
3. Pair it with `pending_count()` when you need to distinguish an idle worker from a stopped logger that still has backlog.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-last-error
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read the last error recorded by the async logger worker during runtime failure handling.
|
||||
update-time: 20260614
|
||||
description: Read the last error string recorded by the async logger worker after run() resets and runtime failure capture.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -33,10 +33,13 @@ pub fn[S] AsyncLogger::last_error(self : AsyncLogger[S]) -> String {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `run()` resets the stored error string when the worker starts.
|
||||
- A later `run()` clears the stored error string only after that run has actually started.
|
||||
- If the worker loop fails, the error text is captured from the raised exception.
|
||||
- An empty string normally means no failure has been recorded.
|
||||
- Once a failure string is recorded, it stays in place until a later `run()` invocation actually starts and clears it.
|
||||
- Failure-driven shutdown does not clear the stored error string by itself, so the same `last_error()` text can remain visible even after the logger is already closed.
|
||||
- This helper reports worker execution errors, not ordinary overflow or backpressure conditions.
|
||||
- That reset happens before the restarted worker resumes drain work.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -67,10 +70,18 @@ In this example, the helper provides the textual failure detail without building
|
||||
e.g.:
|
||||
- If no runtime failure has occurred, the method returns an empty string.
|
||||
|
||||
- An empty string does not prove the queue is empty or the worker is idle; it only means no failure string is currently recorded.
|
||||
|
||||
- If callers need broader context than just the error text, they should use `state()`.
|
||||
|
||||
- `close()` or `shutdown()` do not clear a previously recorded error string by themselves; the reset happens only after a later `run()` has already started.
|
||||
|
||||
- If the same error string is still present after shutdown, that does not by itself mean cleanup was skipped; the logger may already be `is_closed=true` while the remaining pending-versus-dropped outcome still reflects the active runtime's shutdown path.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Read this helper together with `has_failed()` when interpreting worker health.
|
||||
|
||||
2. The stored value is a diagnostic string, not a typed error object.
|
||||
|
||||
3. Pair it with `is_running()` or `pending_count()` when you need to know whether failure left the logger with unfinished backlog, because the previous error string can coexist with remaining pending records until later cleanup or restart.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-log
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
update-time: 20260614
|
||||
description: Enqueue a record into the async logger with an explicit level, message, optional fields, and optional target override.
|
||||
key-word:
|
||||
- async
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Async-logger-log
|
||||
|
||||
Enqueue a record into the async logger with an explicit level and message. This is the core write API behind all async level-specific convenience methods.
|
||||
Enqueue a record into the async logger with an explicit level and message. This is the core write API behind all async level-specific convenience methods and the only built-in async write API that accepts a per-call target override.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -43,10 +43,14 @@ pub async fn[S] AsyncLogger::log(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The logger checks `is_enabled(level)` before building a record.
|
||||
- Compatibility runtimes that guard closed writes first can return immediately when `is_closed()` is already `true`, before level checks, record construction, patch logic, filter logic, or queue work.
|
||||
- Otherwise the logger checks `is_enabled(level)` before building a record.
|
||||
- If `target` is empty, the logger uses its stored default target. If `target` is non-empty, that value overrides the stored target for this call only.
|
||||
- Context fields, patch logic, and filter logic are applied before enqueue.
|
||||
- If timestamping is enabled, `@env.now()` is captured before the record enters the queue.
|
||||
- Overflow behavior depends on the configured `AsyncOverflowPolicy`.
|
||||
- Closed-on-log behavior is runtime-dependent: compatibility runtimes short-circuit before record-building work, while native-worker runtimes may still build, patch, and filter the record before queue operations treat a closed queue as a non-accepted write.
|
||||
- In the tested blocking-policy path, a late write against an already closed logger does not become a newly accepted pending record and does not add another dropped record; it simply fails to enter the queue after any runtime-specific pre-queue work finishes.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -56,7 +60,7 @@ Here are some specific examples provided.
|
||||
|
||||
When code should choose level, fields, and target per event:
|
||||
```moonbit
|
||||
await logger.log(
|
||||
logger.log(
|
||||
@bitlogger.Level::Info,
|
||||
"worker started",
|
||||
fields=[@bitlogger.field("job", "sync")],
|
||||
@@ -64,13 +68,22 @@ await logger.log(
|
||||
)
|
||||
```
|
||||
|
||||
In this example, all per-record inputs are supplied explicitly.
|
||||
In this example, the record overrides the logger's stored target only for this call.
|
||||
|
||||
#### When Reuse The Stored Async Target
|
||||
|
||||
When a call should keep the logger's existing target:
|
||||
```moonbit
|
||||
logger.log(@bitlogger.Level::Warn, "slow request")
|
||||
```
|
||||
|
||||
In this example, the logger falls back to its stored target because no `target=` override is provided.
|
||||
|
||||
#### When Build Higher-level Async Logging Helpers
|
||||
|
||||
When application code wants a custom wrapper around the base API:
|
||||
```moonbit
|
||||
await logger.log(@bitlogger.Level::Warn, "slow request")
|
||||
logger.log(@bitlogger.Level::Warn, "slow request")
|
||||
```
|
||||
|
||||
In this example, `log(...)` acts as the common primitive under custom wrappers or convenience methods.
|
||||
@@ -82,8 +95,14 @@ e.g.:
|
||||
|
||||
- If the logger is closed or overflow policy rejects the record, enqueue may not proceed as a normal accepted write.
|
||||
|
||||
- A closed queue does not count as a newly accepted pending record.
|
||||
|
||||
- On compatibility runtimes, a late call after close can be skipped before patch or filter logic runs at all.
|
||||
|
||||
- On native-worker runtimes, a late call after close can still execute patch and filter logic before the queue rejects the write.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this API when the call site needs full control instead of a fixed severity helper.
|
||||
|
||||
2. Prefer `info()`, `warn()`, and the other shortcuts when only the level differs.
|
||||
2. Prefer `info()`, `warn()`, and the other shortcuts when only the level differs and no per-call target override is needed.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-pending-count
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read the current number of queued records that have not yet been drained by the async logger worker.
|
||||
update-time: 20260614
|
||||
description: Read the current number of queued records that have not yet been drained or cleared from the async logger pipeline.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -35,6 +35,8 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The count increases when records are accepted into the queue.
|
||||
- The count decreases as the worker drains records.
|
||||
- The count is also reset to `0` when queued records are abandoned through clear-close paths such as `close(clear=true)`.
|
||||
- Log attempts against a closed queue do not create new pending backlog.
|
||||
- This is a point-in-time metric and may change immediately after it is read.
|
||||
- Use this helper when a single backlog number is enough and a full `state()` snapshot is unnecessary.
|
||||
|
||||
@@ -67,6 +69,12 @@ In this example, the queue backlog is checked directly.
|
||||
e.g.:
|
||||
- If the worker is not running, `pending_count()` may stay above `0` until records are drained or cleared.
|
||||
|
||||
- If `wait_idle()` returns early because `has_failed()` became `true`, `pending_count()` may still be above `0` until later cleanup or clear-close handling runs.
|
||||
- In the current tested split, that later cleanup can either force the leftover pending item into `dropped_count()` on native-worker shutdown paths or leave the closed-queue remainder visible in `pending_count()` on compatibility shutdown paths.
|
||||
- That means `pending_count()` can still stay above `0` even after `is_closed=true` on compatibility-style shutdown paths, because closure there does not necessarily convert the leftover failed backlog into dropped records.
|
||||
|
||||
- A later restarted `run()` can still drain that retained backlog after failure-reset startup, so a nonzero pending count after failure is not necessarily a permanent terminal state.
|
||||
|
||||
- If the queue is empty, the method simply returns `0`.
|
||||
|
||||
### Notes
|
||||
@@ -74,3 +82,5 @@ e.g.:
|
||||
1. Use `state()` when you also need dropped counts, failure state, or runtime mode.
|
||||
|
||||
2. This helper is useful for lightweight health checks and tests.
|
||||
|
||||
3. Pair it with `is_running()` or `has_failed()` when backlog alone is not enough to explain whether the worker is actively draining, stopped, or failed.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-run
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Start the async logger worker loop so queued records are drained to the underlying sink.
|
||||
update-time: 20260614
|
||||
description: Start the async logger worker loop so queued records are drained to the underlying sink while lifecycle and failure state are reset and updated around execution.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Async-logger-run
|
||||
|
||||
Start the async logger worker loop. This is the core runtime API that drains queued records to the underlying sink and updates worker lifecycle state.
|
||||
Start the async logger worker loop. This is the core runtime API that drains queued records to the underlying sink and updates worker lifecycle state around that drain loop.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -33,10 +33,14 @@ pub async fn[S : @bitlogger.Sink] AsyncLogger::run(self : AsyncLogger[S]) -> Uni
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `run()` sets `is_running` to `true` while the worker loop is active.
|
||||
- It clears previous failure state before worker execution begins.
|
||||
- On failure, the logger records `has_failed=true` and stores the error text in `last_error`.
|
||||
- The worker exits when the queue is closed or when a failure aborts processing.
|
||||
- `run()` sets `is_running` to `true` before worker execution begins.
|
||||
- Every invocation clears previous failure state first by setting `has_failed=false` and `last_error()` to an empty string once that `run()` call has actually started executing.
|
||||
- The method then keeps draining records until `queue.get()` stops with `AsyncLoggerClosed` or a worker error escapes.
|
||||
- On a normal queue-close exit, `run()` clears `is_running` and returns normally.
|
||||
- On failure, the logger records `has_failed=true`, stores the error text in `last_error`, clears `is_running`, and then raises the error back out of `run()`.
|
||||
- A worker failure does not guarantee the async backlog was fully drained first. If the failure happens after some records were already written, later queued records can remain pending when `run()` exits.
|
||||
- A later `run()` invocation can resume draining that retained backlog, but the stale failure flag and stale `last_error()` value are only cleared after the new worker call actually begins running.
|
||||
- This helper does not enforce a single-worker guard by itself, so the public contract should be treated as application-controlled worker startup rather than an API that deduplicates repeated `run()` calls.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -68,12 +72,22 @@ In this example, the application decides when the worker begins instead of hidin
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the worker loop fails, `has_failed()` becomes `true` and `last_error()` stores the error text.
|
||||
- If the worker loop fails, `has_failed()` becomes `true`, `last_error()` stores the error text, and `run()` raises that failure to the caller.
|
||||
|
||||
- After a failed run, `pending_count()` can still be greater than zero until later shutdown or restart logic finishes handling the retained backlog.
|
||||
|
||||
- If `run()` is never started, accepted records may remain queued and not reach the sink.
|
||||
|
||||
- A later `run()` attempt starts from a fresh failure flag and empty `last_error()` string once that retrying worker has actually started, even if an earlier run failed.
|
||||
|
||||
- Starting more than one `run()` task for the same logger is not prevented by this method and can produce application-level worker coordination bugs.
|
||||
|
||||
### Notes
|
||||
|
||||
1. `async_logger(...)` only constructs the logger; `run()` is what activates queue draining.
|
||||
|
||||
2. Pair this API with `shutdown()` for a complete worker lifecycle.
|
||||
|
||||
3. Pair it with `has_failed()`, `last_error()`, or `state()` when tests need to inspect how a worker exit affected logger health.
|
||||
|
||||
4. Start one deliberate worker task per logger unless your own code is intentionally coordinating a different pattern.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-shutdown
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Gracefully stop an async logger by waiting for idle or clearing queued work, then waiting for the worker to finish.
|
||||
update-time: 20260614
|
||||
description: Gracefully stop an async logger by waiting for idle or clearing queued work, with worker-wait behavior depending on the active async runtime.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -35,9 +35,14 @@ pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = fal
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `clear=false` first waits for idle, then closes the logger.
|
||||
- If backlog still remains after waiting, shutdown falls back to `close(clear=true)`.
|
||||
- `clear=true` immediately closes and abandons pending records.
|
||||
- The method waits until `is_running()` becomes `false` before returning.
|
||||
- In runtimes where shutdown clearing after idle is enabled, remaining backlog after `wait_idle()` triggers a fallback `close(clear=true)`.
|
||||
- `clear=true` immediately closes and abandons pending records, even if no worker was ever started for that logger.
|
||||
- In runtimes where shutdown waits for workers, the method then waits until `is_running()` becomes `false` before returning.
|
||||
- In the current backend split, native-worker runtimes enable both the post-`wait_idle()` clear fallback and the final wait-for-worker phase, while compatibility runtimes skip both extra steps.
|
||||
- That means a failure-short-circuited `wait_idle()` can still be followed by forced pending-to-dropped cleanup on native-worker runtimes, while compatibility runtimes close without that extra forced clear step.
|
||||
- In the current tested failure path, native-worker shutdown turns the leftover pending item into one more dropped record, while compatibility shutdown leaves that leftover closed-queue count in `pending_count()` instead.
|
||||
- Shutdown itself does not clear retained worker failure state. If a previous `run()` already recorded `has_failed=true` and a non-empty `last_error()`, those diagnostics can remain visible after shutdown completes.
|
||||
- Because `clear=false` delegates to `wait_idle()` first, shutdown can also wait indefinitely when pending records exist but no worker is making progress and no failure flag is raised.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -47,7 +52,7 @@ Here are some specific examples provided.
|
||||
|
||||
When a service should stop logging only after queued records are drained:
|
||||
```moonbit
|
||||
await logger.shutdown()
|
||||
logger.shutdown()
|
||||
```
|
||||
|
||||
In this example, the logger waits for normal drain behavior before final closure.
|
||||
@@ -56,7 +61,7 @@ In this example, the logger waits for normal drain behavior before final closure
|
||||
|
||||
When teardown should prefer speed over preserving backlog:
|
||||
```moonbit
|
||||
await logger.shutdown(clear=true)
|
||||
logger.shutdown(clear=true)
|
||||
```
|
||||
|
||||
In this example, pending work is abandoned intentionally so shutdown can complete sooner.
|
||||
@@ -66,10 +71,27 @@ In this example, pending work is abandoned intentionally so shutdown can complet
|
||||
e.g.:
|
||||
- If `clear=true`, pending records are intentionally dropped rather than drained.
|
||||
|
||||
- If `wait_idle()` returns early because the worker failed, shutdown behavior after that point still depends on the active runtime's fallback and worker-wait rules.
|
||||
|
||||
- After a worker failure, native-worker shutdown may convert the remaining backlog into dropped records, while compatibility shutdown can leave the pending counter reflecting that leftover closed queue state.
|
||||
- In the current direct regression coverage, that split appears as `pending_count() == 0` and `dropped_count()` increasing on native-worker runtimes, versus `pending_count() > 0` and no extra dropped cleanup on compatibility runtimes.
|
||||
|
||||
- Even after shutdown finishes with `is_closed=true`, callers can still observe retained `has_failed()` and `last_error()` from an earlier worker failure.
|
||||
|
||||
- In compatibility-style runtimes without background-worker waiting, shutdown still closes the logger but may not perform the extra wait-for-worker phase described for native-worker runtimes.
|
||||
|
||||
- If pending work exists but no worker was started, `shutdown(clear=false)` may never reach its later close step because it is still waiting inside `wait_idle()`.
|
||||
|
||||
- If callers skip `shutdown()` and only inspect flags manually, it is easier to leave the worker lifecycle in an unclear state.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this API over raw `close()` in normal application shutdown paths.
|
||||
|
||||
2. Choose `clear=true` only when loss of queued records is acceptable.
|
||||
2. Exact post-close waiting behavior depends on the active async runtime mode.
|
||||
|
||||
3. Choose `clear=true` only when loss of queued records is acceptable.
|
||||
|
||||
4. Pair it with `state()` or focused counters when tests need to assert whether shutdown drained backlog or converted it into dropped records.
|
||||
|
||||
5. Prefer `shutdown(clear=true)` when teardown must not depend on a still-running drain worker.
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
name: async-logger-state-new
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Construct an AsyncLoggerState snapshot from explicit runtime, queue, lifecycle, failure, and flush-policy values without probing a live logger.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
- state
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-state-new
|
||||
|
||||
Construct an `AsyncLoggerState` snapshot from explicit runtime, queue, lifecycle, and failure values. This is the low-level constructor behind the public async logger state shape used in diagnostics.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub fn AsyncLoggerState::new(
|
||||
runtime : AsyncRuntimeState,
|
||||
pending_count : Int,
|
||||
dropped_count : Int,
|
||||
is_closed : Bool,
|
||||
is_running : Bool,
|
||||
has_failed : Bool,
|
||||
last_error : String,
|
||||
flush_policy : AsyncFlushPolicy,
|
||||
) -> AsyncLoggerState {
|
||||
```
|
||||
|
||||
#### input
|
||||
|
||||
- `runtime : AsyncRuntimeState` - Embedded backend-level runtime snapshot.
|
||||
- `pending_count : Int` - Current async queue backlog.
|
||||
- `dropped_count : Int` - Current dropped-record count.
|
||||
- `is_closed : Bool` - Whether the logger has been closed.
|
||||
- `is_running : Bool` - Whether the logger worker loop is currently running.
|
||||
- `has_failed : Bool` - Whether the logger has recorded a runtime failure state.
|
||||
- `last_error : String` - Latest error text, or an empty string when no failure has been recorded.
|
||||
- `flush_policy : AsyncFlushPolicy` - Active async flush policy for the logger.
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerState` - Full async logger snapshot containing the supplied runtime, queue, lifecycle, and failure values.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This constructor simply packages the supplied fields into one public snapshot value.
|
||||
- It does not inspect a live logger instance by itself.
|
||||
- `AsyncLogger::state()` is the higher-level API that reads these values from a concrete logger.
|
||||
- It also does not validate whether the supplied fields represent a combination that could come from one real logger instant.
|
||||
- The supplied `runtime : AsyncRuntimeState` is stored exactly as provided; this constructor does not recompute `mode` or `background_worker` from the active backend.
|
||||
- The constructed value matches the same public shape used by async logger serializers.
|
||||
- Because `AsyncLoggerState` is only a data snapshot type, this constructor is mainly useful for tests, adapters, and synthetic diagnostics rather than ordinary logger inspection.
|
||||
- Serialization helpers accept any `AsyncLoggerState` value, including hand-built ones from this constructor.
|
||||
- That includes combinations such as `has_failed=true` together with non-zero `pending_count` or a retained `last_error`, and even a manually chosen runtime snapshot that does not match the current backend, all of which are valid for diagnostic snapshots and test fixtures.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Hand-built Async Logger Snapshot
|
||||
|
||||
When tests or adapters should construct a full async logger state explicitly:
|
||||
```moonbit
|
||||
let state = AsyncLoggerState::new(
|
||||
runtime=AsyncRuntimeState::new(AsyncRuntimeMode::Compatibility, false),
|
||||
pending_count=0,
|
||||
dropped_count=0,
|
||||
is_closed=false,
|
||||
is_running=true,
|
||||
has_failed=false,
|
||||
last_error="",
|
||||
flush_policy=AsyncFlushPolicy::Never,
|
||||
)
|
||||
```
|
||||
|
||||
In this example, a complete async logger snapshot is assembled directly without querying a live logger instance.
|
||||
|
||||
#### When Need Structured Diagnostics Input Before Serialization
|
||||
|
||||
When code should prepare a typed logger state value for later export:
|
||||
```moonbit
|
||||
let state = AsyncLoggerState::new(
|
||||
runtime=async_runtime_state(),
|
||||
pending_count=logger.pending_count(),
|
||||
dropped_count=logger.dropped_count(),
|
||||
is_closed=logger.is_closed(),
|
||||
is_running=logger.is_running(),
|
||||
has_failed=logger.has_failed(),
|
||||
last_error=logger.last_error(),
|
||||
flush_policy=logger.flush_policy(),
|
||||
)
|
||||
```
|
||||
|
||||
In this example, callers still use the direct constructor while making each diagnostic input explicit.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- This constructor itself does not have a normal failure mode; it only packages the provided values.
|
||||
|
||||
- If callers want a snapshot directly from one live logger instance, `AsyncLogger::state()` is the simpler API.
|
||||
|
||||
- If callers manually combine a runtime snapshot, counters, or flush policy that do not actually belong together, the constructor still accepts that synthetic snapshot.
|
||||
|
||||
- If callers want the current backend-derived runtime pair instead of a synthetic one, they must pass `async_runtime_state()` explicitly or use `AsyncLogger::state()`.
|
||||
|
||||
- This constructor does not apply cleanup semantics such as clearing `last_error` on restart or draining pending records; callers must provide those fields exactly as they want them represented.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when code should construct an `AsyncLoggerState` value explicitly.
|
||||
|
||||
2. Pair it with `async_logger_state_to_json(...)` or `stringify_async_logger_state(...)` when the snapshot should be exported.
|
||||
|
||||
3. Prefer `AsyncLogger::state()` when the goal is to report the actual current state of one live logger instance.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-state-to-json
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Convert an AsyncLoggerState snapshot into a JSON value for diagnostics and transport.
|
||||
update-time: 20260614
|
||||
description: Convert an AsyncLoggerState snapshot into a JSON value for diagnostics and transport using the canonical nested runtime shape and flush-policy labels.
|
||||
key-word:
|
||||
- async
|
||||
- state
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Async-logger-state-to-json
|
||||
|
||||
Convert `AsyncLoggerState` into a `JsonValue`. This helper is the structured export path for async logger runtime snapshots when callers want machine-readable diagnostics instead of a plain string.
|
||||
Convert `AsyncLoggerState` into a `JsonValue`. This helper is the structured export path for async logger runtime snapshots or manually constructed state values when callers want machine-readable diagnostics instead of a plain string.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -23,7 +23,7 @@ pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.Json
|
||||
|
||||
#### input
|
||||
|
||||
- `state : AsyncLoggerState` - Snapshot produced by `AsyncLogger::state()`.
|
||||
- `state : AsyncLoggerState` - Snapshot produced by `AsyncLogger::state()` or any manually constructed `AsyncLoggerState` value.
|
||||
|
||||
#### output
|
||||
|
||||
@@ -34,9 +34,15 @@ pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.Json
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The JSON includes runtime mode, worker support, queue counters, lifecycle flags, last error, and flush policy.
|
||||
- The top-level fields are `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`.
|
||||
- The nested `runtime` field reuses `async_runtime_state_to_json(...)`, and `flush_policy` is serialized with the canonical labels `Never`, `Batch`, or `Shutdown`.
|
||||
- The public helper returns the same internal JSON snapshot shape used by `stringify_async_logger_state(...)`, so both export paths stay aligned without duplicate field assembly logic.
|
||||
- This helper is suitable for health endpoints, diagnostics payloads, and custom serialization flows.
|
||||
- It shares the same stable field names used by `stringify_async_logger_state(...)`.
|
||||
- The state must already have been captured before serialization.
|
||||
- The state must already have been captured or constructed before serialization.
|
||||
- Serialization preserves whatever snapshot combination it receives, including failure flags together with remaining backlog counts.
|
||||
- This helper never rereads a logger instance by itself. If callers pass an older or manually constructed `AsyncLoggerState`, the JSON reflects that provided value exactly rather than refreshing fields from live runtime state.
|
||||
- It also does not normalize mixed diagnostic combinations. If the provided snapshot says `is_closed=true` together with retained `has_failed=true`, `last_error`, or non-zero backlog counters, those exact combinations are emitted unchanged.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -68,9 +74,17 @@ e.g.:
|
||||
|
||||
- If the queue is empty, `pending_count` and `dropped_count` are still serialized normally as numeric values.
|
||||
|
||||
- If `has_failed` is `true`, serialization does not force `pending_count` to `0` or clear `last_error`; it reports the snapshot exactly as provided.
|
||||
|
||||
- If callers need newer logger data, they must capture a fresh `AsyncLogger::state()` first instead of expecting JSON conversion itself to refresh stale fields.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this API when downstream code wants a JSON value rather than a ready-made string.
|
||||
1. This helper preserves the nested runtime snapshot instead of flattening `mode` and `background_worker` onto the top level.
|
||||
|
||||
2. Pair it with `AsyncLogger::state()` to capture the snapshot first.
|
||||
2. The resulting object matches the compact string form produced by `stringify_async_logger_state(...)` after JSON stringification.
|
||||
|
||||
3. Use this API when downstream code wants a JSON value rather than a ready-made string.
|
||||
|
||||
4. Pair it with `AsyncLogger::state()` when you want current logger data, or with `AsyncLoggerState::new(...)` when tests or adapters are exporting a synthetic snapshot.
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
name: async-logger-state-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public async logger state alias used for queue, lifecycle, runtime, and flush-policy diagnostics.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
- state
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-state-type
|
||||
|
||||
`AsyncLoggerState` is the public snapshot type used to describe an async logger's runtime status. It is a direct alias to the async logger state model returned by `AsyncLogger::state()` and used by async diagnostics serializers.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type AsyncLoggerState = @utils.AsyncLoggerState
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerState` - Public async logger snapshot containing `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a live logger handle.
|
||||
- The `runtime` field embeds an `AsyncRuntimeState` snapshot.
|
||||
- The remaining fields capture queue counts, lifecycle status, failure state, last error text, and active flush policy.
|
||||
- `AsyncLogger::state()` returns this type directly, while `async_logger_state_to_json(...)` and `stringify_async_logger_state(...)` export the same data shape for diagnostics.
|
||||
- `AsyncLogger::state()` currently builds this snapshot from `async_runtime_state()` plus the logger's current counters, lifecycle flags, last error, and flush policy.
|
||||
- When the value comes from `AsyncLogger::state()`, the fields are read one by one rather than through a transactional snapshot primitive.
|
||||
- `AsyncLoggerState::new(...)` can also construct this type manually, but manual construction is synthetic snapshot data and does not read one live logger instant by itself.
|
||||
- The type itself does not distinguish live logger snapshots from hand-built ones; callers must track whether a given `AsyncLoggerState` value came from `AsyncLogger::state()` or from manual construction.
|
||||
- When a live snapshot is taken after worker failure, `has_failed=true`, a retained `last_error`, and non-zero `pending_count` may legitimately coexist until later cleanup or restart.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Typed Snapshot For Async Diagnostics
|
||||
|
||||
When application code should inspect async logger state before deciding how to report it:
|
||||
```moonbit
|
||||
let state : AsyncLoggerState = logger.state()
|
||||
```
|
||||
|
||||
In this example, queue, lifecycle, and runtime information stay available as structured data.
|
||||
|
||||
#### When Need To Branch On Failure Or Backlog
|
||||
|
||||
When code should react to the current async logger condition:
|
||||
```moonbit
|
||||
let state = logger.state()
|
||||
if state.has_failed || state.pending_count > 0 {
|
||||
println(stringify_async_logger_state(state, pretty=true))
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the typed snapshot supports both logic and later export.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `AsyncLoggerState` itself does not have a runtime failure mode.
|
||||
|
||||
- `last_error` may be an empty string when no failure has occurred, which is normal and not a special error condition by itself.
|
||||
|
||||
- Because this is just a data shape, manual construction can represent combinations that do not come from a live logger at one exact instant.
|
||||
|
||||
- Receiving an `AsyncLoggerState` value alone does not prove it came from one current logger read rather than from a synthetic constructor path.
|
||||
|
||||
- This type does not imply cleanup semantics by itself; values only report the supplied or captured fields and do not drain backlog or clear recorded failure state.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `AsyncLogger::state()` when you need a value of this type from one logger instance.
|
||||
|
||||
2. Use `AsyncRuntimeState` when only backend-level capability information is needed and logger-instance state is unnecessary.
|
||||
|
||||
3. Use `async_logger_state_to_json(...)` or `stringify_async_logger_state(...)` when this snapshot should leave typed space and become stable diagnostic output.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-state
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read a full async logger runtime snapshot including queue counters, lifecycle flags, and runtime mode.
|
||||
update-time: 20260614
|
||||
description: Read a full async logger runtime snapshot including the embedded runtime snapshot, queue counters, lifecycle flags, last error, and flush policy.
|
||||
key-word:
|
||||
- async
|
||||
- state
|
||||
@@ -34,9 +34,16 @@ pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {}
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `AsyncLoggerState` includes `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`.
|
||||
- `state()` returns a point-in-time snapshot rather than a live handle.
|
||||
- `state()` returns a value snapshot rather than a live handle.
|
||||
- This helper is equivalent to `AsyncLoggerState::new(async_runtime_state(), self.pending_count(), self.dropped_count(), self.is_closed(), self.is_running(), self.has_failed(), self.last_error(), self.flush_policy())`.
|
||||
- `async_logger_state_to_json(...)` and `stringify_async_logger_state(...)` convert the snapshot to stable diagnostic output.
|
||||
- `runtime` embeds the result of `async_runtime_state()` so callers do not need to join separate helpers manually.
|
||||
- `runtime` embeds the result of `async_runtime_state()` from the moment `state()` is called, so callers do not need to join separate helpers manually.
|
||||
- The runtime portion is therefore recomputed from the active backend helper on each call, while the remaining fields come from the logger's current counters, flags, and flush policy at that same general moment.
|
||||
- Because the snapshot is assembled field by field when `state()` is called, later logger changes require calling `state()` again rather than reusing an older `AsyncLoggerState` value as if it refreshed itself.
|
||||
- That field-by-field assembly also means this helper is not an atomic freeze across all refs; under concurrent logger activity, neighboring fields can reflect slightly different instants.
|
||||
- After a worker failure, `has_failed=true`, a non-empty `last_error`, and `pending_count>0` can legitimately appear together in one snapshot until later cleanup or a later started `run()` changes them.
|
||||
- After shutdown cleanup on an already failed logger, snapshots can also legitimately show `is_closed=true` together with retained `has_failed=true` and the same `last_error()`, while `pending_count` versus `dropped_count` still reflects the active runtime's cleanup path.
|
||||
- `state()` only reports the current field values; it does not clear failure state, drain backlog, or synchronize pending work by itself.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -66,6 +73,8 @@ if state.has_failed {
|
||||
|
||||
In this example, the same snapshot object works for conditional diagnostics and serialization.
|
||||
|
||||
And the reported failure fields can still appear together with non-zero backlog when a worker stopped early.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -73,8 +82,22 @@ e.g.:
|
||||
|
||||
- If the queue is empty, `pending_count` is `0`; this is normal and not a special error condition.
|
||||
|
||||
- `flush_policy` reports the logger's configured async flush mode, not whether a flush has already happened.
|
||||
|
||||
- The embedded `runtime` object is also just a snapshot of the current backend helper result at read time; `state()` does not cache it onto the logger for later reuse.
|
||||
|
||||
- If concurrent logger activity is still changing counters or flags while `state()` runs, the returned value is still useful for diagnostics but should not be treated as a transactional snapshot.
|
||||
|
||||
- A snapshot showing `has_failed=true` does not imply `pending_count` is already `0`; remaining queued records may still be visible until later cleanup or restart.
|
||||
|
||||
- A snapshot showing `is_closed=true` also does not imply failure state was cleared; after failure-driven shutdown, `has_failed=true` and the recorded `last_error` can still remain visible until a later `run()` actually restarts the logger.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this API over manually combining `pending_count()`, `dropped_count()`, and runtime-mode helpers.
|
||||
|
||||
2. Use `pretty=true` when emitting logs for humans and the compact form for machine-oriented payloads.
|
||||
|
||||
3. Use `AsyncLoggerState::new(...)` only when tests or adapters need to construct a manual snapshot instead of reading one directly from a logger instance.
|
||||
|
||||
4. If consumers need stronger cross-field consistency than a diagnostic snapshot, they should not assume `state()` provides an atomic read barrier.
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: async-logger-to-library-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
description: Convert a full async logger into the narrower library-facing async facade without rebuilding or detaching the underlying async state.
|
||||
key-word:
|
||||
- async
|
||||
- library
|
||||
- facade
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-to-library-async-logger
|
||||
|
||||
Convert `AsyncLogger[S]` into `LibraryAsyncLogger[S]`. This keeps the same async queue and sink behavior while projecting the value onto the smaller library-facing async surface.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub fn[S] AsyncLogger::to_library_async_logger(self : AsyncLogger[S]) -> LibraryAsyncLogger[S] {}
|
||||
```
|
||||
|
||||
#### input
|
||||
|
||||
- `self : AsyncLogger[S]` - Full async logger to project into the library facade.
|
||||
|
||||
#### output
|
||||
|
||||
- `LibraryAsyncLogger[S]` - Narrower library-facing wrapper over the same async logger state.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This conversion does not rebuild the queue, sink, or runtime state.
|
||||
- Target, min level, async config, flush behavior, pending counts, and failure state are preserved because the same underlying async logger value is wrapped.
|
||||
- The original `AsyncLogger[S]` handle remains the same live logger. If caller code keeps that original value, later facade calls and later unwraps still observe the same shared queue, counters, sink helpers, and lifecycle mutations.
|
||||
- The returned facade keeps library-facing async operations including `log(...)`, `run()`, and `shutdown(...)`.
|
||||
- Async inspection helpers and broader composition APIs remain on the underlying `AsyncLogger[S]` and are intentionally hidden until `to_async_logger()` is used again.
|
||||
- If later facade-level `run()` or `shutdown()` calls record worker failure, leave backlog behind, or follow runtime-dependent shutdown cleanup rules, unwrapping later still exposes that same post-call state instead of a translated facade copy.
|
||||
- That includes states where delegated shutdown already finished with `is_closed=true` while retained `has_failed()` and `last_error()` remain on the wrapped logger, together with the same runtime-dependent pending-versus-dropped cleanup outcome.
|
||||
- When `S` itself exposes richer runtime helpers, projecting to the library facade does not strip those capabilities from the wrapped logger; they are still reachable after `to_async_logger()`.
|
||||
- When `S` is `RuntimeSink`, projection also preserves queued runtime state and file-backed runtime helper behavior behind the facade instead of replacing them with a library-specific copy.
|
||||
- Unwrapping later with `to_async_logger()` therefore exposes the same queue counters, failure snapshots, file state, and runtime file controls that the original async logger already carried.
|
||||
- That also means runtime sink mutations still alias in both directions: changing file append mode, auto-flush, rotation, or other sink helper state through a later unwrapped logger changes the same live runtime sink that the original `AsyncLogger[S]` already held.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need To Expose A Narrower Async Type
|
||||
|
||||
When internal setup uses the full async logger API but public library code should return a smaller facade:
|
||||
```moonbit
|
||||
let logger = async_logger(console_sink(), target="lib.async")
|
||||
let public_logger = logger.to_library_async_logger()
|
||||
```
|
||||
|
||||
In this example, `public_logger` keeps the same async behavior but exposes the library-facing facade.
|
||||
|
||||
#### When Need To Narrow Surface Without Resetting Runtime State
|
||||
|
||||
When an already-used async logger should be projected to a library boundary without changing its current state:
|
||||
```moonbit
|
||||
let full = build_async_logger(config)
|
||||
let public_logger = full.to_library_async_logger()
|
||||
ignore(public_logger.is_enabled(@bitlogger.Level::Info))
|
||||
```
|
||||
|
||||
In this example, the projection changes the exposed type only; it does not rebuild queue or lifecycle state.
|
||||
|
||||
If `full` is still kept elsewhere, it continues sharing that same live runtime state with `public_logger`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If callers later need APIs outside the library facade, they must unwrap with `to_async_logger()`.
|
||||
|
||||
- The conversion does not clear pending items or reset runtime state.
|
||||
|
||||
- If callers later need state helpers such as `pending_count()` or `state()`, they must unwrap again with `to_async_logger()`.
|
||||
|
||||
- Projection does not normalize failure snapshots; a later unwrap can still show combinations such as retained `last_error()` with remaining `pending_count()` when the wrapped async logger really ended up in that state.
|
||||
|
||||
- Projection also does not normalize delegated shutdown results; a later unwrap can still show `is_closed=true` together with retained `has_failed()`, the same `last_error()`, and the same runtime-dependent leftover backlog or dropped-count cleanup that accumulated behind the facade.
|
||||
|
||||
- Projection also does not normalize richer runtime sink state; if the original async logger already carried queued runtime data or file-backed helper state, a later unwrap still exposes that same live state.
|
||||
|
||||
- Projection does not create an isolated wrapper copy. If callers keep the original `AsyncLogger[S]`, then later facade-level writes, shutdown, or sink-helper mutations still affect that original handle too.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this when package boundaries should avoid exposing the full async logger type.
|
||||
|
||||
2. This is a projection API, not a reconfiguration step.
|
||||
|
||||
3. Use `build_library_async_logger(...)` or `build_library_async_text_logger(...)` when construction and narrowing should happen together from config.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-trace
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Enqueue a trace-level record through the async logger using the lowest built-in severity shortcut.
|
||||
update-time: 20260614
|
||||
description: Enqueue a trace-level record through the async logger using the lowest built-in severity shortcut and the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -39,8 +39,9 @@ pub async fn[S] AsyncLogger::trace(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This helper delegates to `log(Level::Trace, ...)`.
|
||||
- This helper delegates to `log(Level::Trace, ..., fields=fields)`.
|
||||
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
|
||||
- This helper does not accept a per-call target override. It uses the logger's stored target unless the logger was derived earlier with `with_target(...)` or `child(...)`.
|
||||
- Trace records are often skipped in production because they are the lowest built-in severity.
|
||||
- Use this helper when explicit trace intent is clearer than a raw `log(...)` call.
|
||||
|
||||
@@ -52,7 +53,7 @@ Here are some specific examples provided.
|
||||
|
||||
When low-level execution flow should be observable during debugging:
|
||||
```moonbit
|
||||
await logger.trace("entered reconciliation step")
|
||||
logger.trace("entered reconciliation step")
|
||||
```
|
||||
|
||||
In this example, the call site makes trace intent explicit.
|
||||
@@ -61,7 +62,7 @@ In this example, the call site makes trace intent explicit.
|
||||
|
||||
When a trace event should carry extra fields:
|
||||
```moonbit
|
||||
await logger.trace(
|
||||
logger.trace(
|
||||
"cache probe",
|
||||
fields=[@bitlogger.field("key", "user:42")],
|
||||
)
|
||||
@@ -80,4 +81,6 @@ e.g.:
|
||||
|
||||
1. Prefer this helper when trace intent is more readable than `log(Level::Trace, ...)`.
|
||||
|
||||
2. Trace-level async logging can increase queue pressure quickly under verbose workloads.
|
||||
2. Use `log(...)` instead when one trace call needs a one-off target override.
|
||||
|
||||
3. Trace-level async logging can increase queue pressure quickly under verbose workloads.
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
name: async-logger-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public asynchronous logger root type used for queue-backed sink-preserving logging pipelines with explicit lifecycle, failure, and flush-callback state.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
- type
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-logger-type
|
||||
|
||||
`AsyncLogger[S]` is the public asynchronous root logger type. It stores a concrete sink type `S` together with queue policy, runtime state counters, and lifecycle flags, then serves as the base value for async composition, worker control, and async write APIs.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub struct AsyncLogger[S] {
|
||||
min_level : @bitlogger.Level
|
||||
target : String
|
||||
timestamp : Bool
|
||||
overflow : AsyncOverflowPolicy
|
||||
max_batch : Int
|
||||
linger_ms : Int
|
||||
flush_policy : AsyncFlushPolicy
|
||||
sink : S
|
||||
flush_sink : (S) -> Int raise
|
||||
context_fields : Array[@bitlogger.Field]
|
||||
filter : (@bitlogger.Record) -> Bool
|
||||
patch : @bitlogger.RecordPatch
|
||||
queue : @async.Queue[@bitlogger.Record]
|
||||
pending_count : Ref[Int]
|
||||
dropped_count : Ref[Int]
|
||||
is_closed : Ref[Bool]
|
||||
is_running : Ref[Bool]
|
||||
has_failed : Ref[Bool]
|
||||
last_error : Ref[String]
|
||||
}
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLogger[S]` - Public queue-backed asynchronous logger value parameterized by the concrete sink type `S`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a public root struct, not a type alias.
|
||||
- The current fields cover targeting, overflow policy, batching, linger timing, flush policy, the wrapped sink, context/filter/patch behavior, queue state, and worker lifecycle flags.
|
||||
- `flush_sink : (S) -> Int raise` stores the raising flush callback used by batch and shutdown flush policies.
|
||||
- `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, and `last_error` are mutable runtime refs that power the higher-level lifecycle and diagnostics helpers.
|
||||
- The sink type parameter is preserved across async composition, which is why helpers such as `with_target(...)`, `with_context_fields(...)`, `with_filter(...)`, and `with_patch(...)` keep returning `AsyncLogger[S]`.
|
||||
- `async_logger(...)` constructs this type as the main asynchronous entry point.
|
||||
- This root type is also what sits underneath both async facade families: `ApplicationAsyncLogger` is a direct alias over the runtime-sink line, while `LibraryAsyncLogger[S]` is a narrowing wrapper around an `AsyncLogger[S]` value.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Typed Root Async Logger Value
|
||||
|
||||
When queue-backed logging should begin from a concrete sink-preserving root object:
|
||||
```moonbit
|
||||
let logger : AsyncLogger[ConsoleSink] = async_logger(console_sink(), target="app.async")
|
||||
```
|
||||
|
||||
In this example, the root async logger keeps the concrete sink type visible for later typed composition.
|
||||
|
||||
#### When Need Worker Control Plus Runtime State
|
||||
|
||||
When code should both enqueue logs and inspect async runtime behavior:
|
||||
```moonbit
|
||||
let logger = async_logger(console_sink(), config=AsyncLoggerConfig::new(max_pending=32))
|
||||
ignore(logger.pending_count())
|
||||
ignore(logger.state())
|
||||
```
|
||||
|
||||
In this example, the root type combines queue-backed logging with explicit runtime observability.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `AsyncLogger[S]` itself does not have a runtime failure mode.
|
||||
|
||||
- Actual enqueue, worker, and flush behavior still depends on the wrapped sink `S`, async runtime support, and the configured queue policy.
|
||||
|
||||
- Post-close logging behavior is not a property of the struct shape alone; it also depends on the active runtime implementation.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `async_logger(...)`, `build_async_logger(...)`, or `build_async_text_logger(...)` when you need a value of this type.
|
||||
|
||||
2. Use `ApplicationAsyncLogger` when application code wants the same full async lifecycle and state helper surface under an app-facing alias.
|
||||
|
||||
3. Use `LibraryAsyncLogger[S]` when a library boundary should intentionally narrow the public async surface and expose broader lifecycle/state helpers only through `to_async_logger()`.
|
||||
|
||||
4. Prefer the method helpers such as `state()`, `has_failed()`, `last_error()`, `is_running()`, and `shutdown()` instead of reading these public fields conceptually as if they were a stable manual mutation surface.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-wait-idle
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Wait until the async logger backlog drains to zero or a worker failure interrupts normal progress.
|
||||
update-time: 20260614
|
||||
description: Wait until the async logger backlog drains to zero or a worker failure interrupts normal progress, using the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -34,8 +34,12 @@ pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {}
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The helper keeps yielding while `pending_count() > 0`.
|
||||
- If `has_failed()` becomes `true`, waiting stops early instead of looping forever.
|
||||
- If `has_failed()` becomes `true`, waiting stops early instead of continuing to spin.
|
||||
- This API does not close the logger or stop the worker.
|
||||
- A return from `wait_idle()` therefore means either backlog reached `0` or failure interrupted normal drain progress.
|
||||
- `wait_idle()` does not clear retained failure state by itself, so if pending records remain after a worker failure, later `wait_idle()` calls also short-circuit until another path changes that state.
|
||||
- A later `run()` can make `wait_idle()` meaningful again for the retained backlog, but only after that new worker invocation has actually started and reset the stale failure flag.
|
||||
- If no worker is draining the queue and no failure flag is raised, `wait_idle()` can wait indefinitely.
|
||||
- It is narrower than `shutdown()` and is useful when the logger should continue to be used later.
|
||||
|
||||
### How to Use
|
||||
@@ -46,7 +50,7 @@ Here are some specific examples provided.
|
||||
|
||||
When code should wait for queued work to flush before continuing:
|
||||
```moonbit
|
||||
await logger.wait_idle()
|
||||
logger.wait_idle()
|
||||
```
|
||||
|
||||
In this example, the caller waits for backlog drain but leaves the logger usable afterward.
|
||||
@@ -55,7 +59,7 @@ In this example, the caller waits for backlog drain but leaves the logger usable
|
||||
|
||||
When a test wants to ensure earlier async logs were processed:
|
||||
```moonbit
|
||||
await logger.wait_idle()
|
||||
logger.wait_idle()
|
||||
println("phase complete")
|
||||
```
|
||||
|
||||
@@ -66,10 +70,17 @@ In this example, the wait acts as a barrier between test phases.
|
||||
e.g.:
|
||||
- If the worker has failed, `wait_idle()` stops waiting even if pending records remain.
|
||||
|
||||
- If the worker was never started, pending records may not drain and callers should not expect idle progress automatically.
|
||||
- If the worker was never started, or if nothing is making pending records decrease, `wait_idle()` can block indefinitely.
|
||||
|
||||
- If callers need backlog cleanup after a failure-short-circuit, they still need a later `close(clear=true)` or `shutdown(...)` path.
|
||||
- In the current direct coverage, `wait_idle()` can return with `pending_count() > 0` after a worker failure, and the later cleanup path may either clear that backlog explicitly or follow the runtime-dependent shutdown split documented on `shutdown(...)`.
|
||||
|
||||
- If callers retry `wait_idle()` immediately after such a failure without restarting the worker or forcing cleanup first, the call can return again with the same retained pending backlog.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when you want a drain barrier without closing the logger.
|
||||
|
||||
2. Prefer `shutdown()` when lifecycle completion matters more than continued reuse.
|
||||
|
||||
3. Pair it with `pending_count()` or `state()` when you need to distinguish true idleness from an early stop caused by worker failure.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-warn
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Enqueue a warning-level record through the async logger using the built-in severity shortcut.
|
||||
update-time: 20260614
|
||||
description: Enqueue a warning-level record through the async logger using the built-in severity shortcut and the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -39,8 +39,9 @@ pub async fn[S] AsyncLogger::warn(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This helper delegates to `log(Level::Warn, ...)`.
|
||||
- This helper delegates to `log(Level::Warn, ..., fields=fields)`.
|
||||
- The record is still subject to min-level gating, patching, filtering, and overflow policy.
|
||||
- This helper does not accept a per-call target override. It uses the logger's stored target unless the logger was derived earlier with `with_target(...)` or `child(...)`.
|
||||
- Warning records are useful for degraded but non-fatal runtime conditions.
|
||||
- Use this helper when a named warning call is clearer than a raw `log(...)` call.
|
||||
|
||||
@@ -52,7 +53,7 @@ Here are some specific examples provided.
|
||||
|
||||
When the system should report a non-fatal problem:
|
||||
```moonbit
|
||||
await logger.warn("retry budget running low")
|
||||
logger.warn("retry budget running low")
|
||||
```
|
||||
|
||||
In this example, the event is surfaced at warning severity without using the generic `log(...)` form.
|
||||
@@ -61,7 +62,7 @@ In this example, the event is surfaced at warning severity without using the gen
|
||||
|
||||
When a warning event should include context:
|
||||
```moonbit
|
||||
await logger.warn(
|
||||
logger.warn(
|
||||
"queue near capacity",
|
||||
fields=[@bitlogger.field("pending", logger.pending_count().to_string())],
|
||||
)
|
||||
@@ -69,6 +70,10 @@ await logger.warn(
|
||||
|
||||
In this example, the warning carries structured operational detail.
|
||||
|
||||
And any shared context already carried by the logger still participates ahead of these per-call fields when the record is built.
|
||||
|
||||
The write still uses the logger's stored target because this shortcut does not take a one-off `target=` override.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -80,4 +85,4 @@ e.g.:
|
||||
|
||||
1. Use this helper for notable but non-fatal async runtime conditions.
|
||||
|
||||
2. Pair warnings with structured fields when operators need quick context.
|
||||
2. Use `log(...)` instead when one warning call must override the target without deriving a new logger value.
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn[S] AsyncLogger::with_context_fields(
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLogger[S]` - A new async logger carrying the shared field set.
|
||||
- `AsyncLogger[S]` - A new async logger value carrying the shared field set.
|
||||
|
||||
### Explanation
|
||||
|
||||
@@ -40,7 +40,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
- Context fields are merged during `log(...)` before enqueue.
|
||||
- When a log call also passes per-record fields, the context fields are placed before those per-call fields.
|
||||
- This API returns a new logger value; it does not mutate the original async logger.
|
||||
- The provided `fields` array replaces the previously stored shared field set on the returned async logger; it does not append onto whatever `context_fields` the source logger already had.
|
||||
- Unlike synchronous `Logger::with_context_fields(...)`, this async variant stores fields directly on `AsyncLogger` instead of changing the visible sink type.
|
||||
- Only the stored `context_fields` value changes. Target, minimum level, timestamp flag, queue configuration, and lifecycle/failure state stay on the same `AsyncLogger[S]` surface.
|
||||
- In the current direct async coverage, the original logger keeps its previous `context_fields`, while the derived logger prepends the stored shared fields ahead of per-call fields exactly once when records are built.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -59,6 +62,8 @@ let logger = async_logger(console_sink(), target="billing")
|
||||
|
||||
In this example, both fields are attached before each record enters the queue.
|
||||
|
||||
And the returned async logger still keeps the same queue-facing API surface as the source logger.
|
||||
|
||||
#### When Build Child Async Loggers For Subsystems
|
||||
|
||||
When a subsystem has both a target and fixed fields:
|
||||
@@ -75,6 +80,8 @@ In this example, target composition and field binding stay separate but work tog
|
||||
e.g.:
|
||||
- If `fields` is empty, the logger remains valid and just adds no extra metadata.
|
||||
|
||||
- If a derived async logger already had shared context fields, calling `with_context_fields(...)` again replaces that stored shared field set on the new derived logger rather than stacking both sets together.
|
||||
|
||||
- If duplicate field keys are provided, all fields are still emitted; conflict handling is left to the consumer side.
|
||||
|
||||
### Notes
|
||||
@@ -82,3 +89,9 @@ e.g.:
|
||||
1. Use this for stable metadata, not highly dynamic event-specific values.
|
||||
|
||||
2. This async variant preserves the visible `AsyncLogger[S]` type while still injecting shared fields.
|
||||
|
||||
3. State helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, and `has_failed()` remain available on the returned logger because the visible async logger surface is preserved.
|
||||
|
||||
4. Use a fresh derived logger when one code path needs shared metadata and another should stay unchanged.
|
||||
|
||||
5. If you need to combine two shared field sets, combine them in the `fields` argument yourself instead of expecting repeated `with_context_fields(...)` calls to accumulate them.
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn[S] AsyncLogger::with_filter(
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLogger[S]` - A new async logger that only enqueues matching records.
|
||||
- `AsyncLogger[S]` - A new async logger value that only enqueues matching records.
|
||||
|
||||
### Explanation
|
||||
|
||||
@@ -39,8 +39,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Filtering happens after record construction and patch application but before enqueue.
|
||||
- Existing filter logic is preserved and combined with the new predicate using logical `and`.
|
||||
- The original async logger is not mutated.
|
||||
- The returned logger is derived from `self`; the original async logger value is not mutated.
|
||||
- Only the stored filter pipeline changes. Target, minimum level, queue configuration, and lifecycle/failure state stay on the same `AsyncLogger[S]` surface.
|
||||
- Filtering avoids unnecessary queue pressure for records that should never be delivered.
|
||||
- In the current direct async coverage, derived filters can compose target, level, and message predicates together while the original logger still accepts writes according to its previous filter state.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -56,6 +58,8 @@ let logger = async_logger(console_sink(), target="service")
|
||||
|
||||
In this example, non-matching records are dropped before they reach the async queue.
|
||||
|
||||
And the returned async logger still keeps the same queue-facing API surface as the source logger.
|
||||
|
||||
#### When Combine Several Async Filter Rules
|
||||
|
||||
When filtering depends on multiple conditions:
|
||||
@@ -80,3 +84,7 @@ e.g.:
|
||||
1. Use this API for selection logic, not record mutation.
|
||||
|
||||
2. Async filtering is especially useful when queue capacity should be reserved for high-value records.
|
||||
|
||||
3. State helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, and `has_failed()` remain available on the returned logger because the visible async logger surface is preserved.
|
||||
|
||||
4. Use a derived logger value when one branch should enforce extra filter rules and the base async logger should stay unchanged.
|
||||
|
||||
@@ -39,8 +39,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `log(...)` checks `is_enabled(level)` before creating a record or touching the queue.
|
||||
- Lower-severity records below `min_level` are skipped before enqueue.
|
||||
- This API replaces the logger threshold and does not alter queue configuration.
|
||||
- The returned logger keeps the same sink, target, and timestamp settings.
|
||||
- The returned logger is derived from `self`; the original async logger value is not mutated.
|
||||
- This API replaces the stored threshold and does not alter queue configuration.
|
||||
- Only `min_level` changes. Sink, target, timestamp flag, and lifecycle/failure state stay on the same `AsyncLogger[S]` surface.
|
||||
- In the current direct async coverage, the derived logger reports the new threshold through `is_enabled(...)`, while the original logger keeps its previous minimum level and still accepts records that remain enabled there.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -56,6 +58,8 @@ let logger = async_logger(console_sink())
|
||||
|
||||
In this example, lower-severity records are skipped before queue pressure increases.
|
||||
|
||||
And the returned async logger still keeps the same queue-facing API surface as the source logger.
|
||||
|
||||
#### When Derive A More Verbose Async Branch
|
||||
|
||||
When one branch of code should keep a different threshold:
|
||||
@@ -78,3 +82,7 @@ e.g.:
|
||||
1. This API reduces async queue pressure by dropping disabled levels before enqueue.
|
||||
|
||||
2. Use it before adding more complex async filtering rules.
|
||||
|
||||
3. State helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, and `has_failed()` remain available on the returned logger because the visible async logger surface is preserved.
|
||||
|
||||
4. Use a derived logger value when one branch should tighten the threshold and the base async logger should keep its broader level gate.
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn[S] AsyncLogger::with_patch(
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLogger[S]` - A new async logger that rewrites each record before filtering and queue insertion.
|
||||
- `AsyncLogger[S]` - A new async logger value that rewrites each record before filtering and queue insertion.
|
||||
|
||||
### Explanation
|
||||
|
||||
@@ -39,8 +39,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Patch logic runs after record creation and field merging but before filtering and enqueue.
|
||||
- Existing patch logic is preserved and composed so the new patch wraps the current one.
|
||||
- The original async logger is not mutated.
|
||||
- The returned logger is derived from `self`; the original async logger value is not mutated.
|
||||
- Only the stored patch pipeline changes. Target, minimum level, queue configuration, and lifecycle/failure state stay on the same `AsyncLogger[S]` surface.
|
||||
- Patching can normalize, redact, or enrich records before they consume queue capacity.
|
||||
- In the current direct async coverage, patched target/message/field changes are visible to later filter logic, and the original async logger still emits unpatched records when used separately.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -58,6 +60,8 @@ let logger = async_logger(console_sink())
|
||||
|
||||
In this example, the added fields are part of the record before filtering and queue insertion.
|
||||
|
||||
And the returned async logger still keeps the same queue-facing API surface as the source logger.
|
||||
|
||||
#### When Need Redaction Before Queueing
|
||||
|
||||
When sensitive fields should be removed early:
|
||||
@@ -80,3 +84,7 @@ e.g.:
|
||||
1. Use patches for transformation, not filtering decisions.
|
||||
|
||||
2. Redaction before enqueue helps keep sensitive data out of the queued pipeline.
|
||||
|
||||
3. State helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, and `has_failed()` remain available on the returned logger because the visible async logger surface is preserved.
|
||||
|
||||
4. Derive a patched logger when one path needs rewritten records and another should keep the original async record shape.
|
||||
|
||||
@@ -38,6 +38,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
- This API replaces the default target instead of composing it.
|
||||
- Per-call `target?` arguments on `log(...)` can still override the default target.
|
||||
- The original logger value is not mutated.
|
||||
- In the current direct async coverage, derived loggers keep existing flags such as `timestamp`, while the original logger still retains its previous target.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -76,3 +77,5 @@ e.g.:
|
||||
1. Use this API for replacement, not parent-child target composition.
|
||||
|
||||
2. It is useful when several subsystems should share one async queue policy.
|
||||
|
||||
3. Use it when you want a derived logger value; the original async logger keeps its earlier default target.
|
||||
|
||||
@@ -37,7 +37,9 @@ Detailed rules explaining key parameters and behaviors
|
||||
- When enabled, `log(...)` captures `@env.now()` before placing the record into the queue.
|
||||
- When disabled, emitted records use `0UL` as the timestamp value.
|
||||
- This setting affects later emitted records only.
|
||||
- Queue, batching, and flush behavior are unchanged.
|
||||
- The returned logger is derived from `self`; the original async logger value is not mutated.
|
||||
- Only the stored `timestamp` flag changes. Target, minimum level, queue configuration, and lifecycle/failure state stay on the same `AsyncLogger[S]` surface.
|
||||
- In the current direct async coverage, a derived timestamp-enabled logger records non-zero timestamps while the original logger continues emitting `0UL` timestamps when it was left disabled.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -53,6 +55,8 @@ let logger = async_logger(console_sink())
|
||||
|
||||
In this example, each record captures its timestamp before entering the async queue.
|
||||
|
||||
And the returned async logger still keeps the same queue-facing API surface as the source logger.
|
||||
|
||||
#### When Need Deterministic Async Records
|
||||
|
||||
When timestamps should be disabled for tests or reduced output:
|
||||
@@ -75,3 +79,7 @@ e.g.:
|
||||
1. This API controls record creation before enqueue, not formatter display policy.
|
||||
|
||||
2. It is useful for tests, deterministic snapshots, and production timing.
|
||||
|
||||
3. State helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, and `has_failed()` remain available on the returned logger because the visible async logger surface is preserved.
|
||||
|
||||
4. Use a derived logger value when only one branch should capture timestamps and the base logger should remain deterministic.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Create an async logger with bounded queueing, overflow policy, lifecycle helpers, and background run control.
|
||||
update-time: 20260614
|
||||
description: Create an async logger with bounded queueing, overflow policy, lifecycle helpers, background run control, and a raising flush callback.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -23,7 +23,7 @@ pub fn[S] async_logger(
|
||||
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
||||
target~ : String = "",
|
||||
flush~ : (S) -> Int = fn(_) { 0 },
|
||||
flush~ : (S) -> Int raise = fn(_) { 0 },
|
||||
) -> AsyncLogger[S] {}
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn[S] async_logger(
|
||||
- `config : AsyncLoggerConfig` - Queue size, overflow behavior, batching, linger, and flush policy.
|
||||
- `min_level : Level` - Level gate applied before enqueue.
|
||||
- `target : String` - Default target for emitted records.
|
||||
- `flush : (S) -> Int` - Flush callback used by batch/shutdown flush policies.
|
||||
- `flush : (S) -> Int raise` - Flush callback used by batch/shutdown flush policies and allowed to raise if sink flushing fails.
|
||||
|
||||
#### output
|
||||
|
||||
@@ -44,10 +44,20 @@ pub fn[S] async_logger(
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `async_logger(...)` only builds the logger. Actual background draining is started by `run()`.
|
||||
- `async_logger(...)` returns the full `AsyncLogger[S]` surface directly. It is therefore the underlying constructor used by both application-facing async aliases and the narrower `LibraryAsyncLogger[S]` wrapper line.
|
||||
- The constructed logger starts with `is_closed=false`, `is_running=false`, `has_failed=false`, `last_error=""`, and zeroed pending/dropped counters.
|
||||
- The constructed logger also keeps the core async target contract unchanged: `log(..., target=...)` can override the target for one call, while fixed-level helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- Unlike synchronous `Logger`, async `with_context_fields(...)` and `bind(...)` preserve the visible `AsyncLogger[S]` type because shared fields are stored directly on the async logger value instead of being modeled as a separate sink wrapper.
|
||||
- `ApplicationAsyncLogger` and `ApplicationTextAsyncLogger` are only alias names over concrete `AsyncLogger[...]` shapes, so they keep the same lifecycle, queue, failure, and state helpers without adding a wrapper layer.
|
||||
- `LibraryAsyncLogger[S]` wraps an `AsyncLogger[S]` value instead of aliasing it. That library facade preserves queue-backed logging behavior, but it narrows the directly exposed helper surface until callers recover the full logger with `to_async_logger()`.
|
||||
- In non-native targets, the implementation uses compatibility behavior while keeping the same public surface.
|
||||
- `src-async` is designed for `native / llvm / js / wasm / wasm-gc`, but current release-facing local verification is stronger for `native / js / wasm / wasm-gc` than for `llvm`.
|
||||
- `llvm` should currently be read as experimental and locally unverified in this environment rather than as a stable checked target.
|
||||
- `flush` is used only when batch or shutdown policy wants explicit flushing.
|
||||
- If the supplied flush callback raises, worker failure state is recorded through `has_failed()` and `last_error()`.
|
||||
- `wait_idle()` is failure-aware rather than a pure backlog-to-zero guarantee. If a worker failure sets `has_failed=true`, waiting stops early and the logger can still report `pending_count() > 0` until later cleanup or restart work happens.
|
||||
- A later `run()` attempt starts by clearing stale failure state back to `has_failed=false` and `last_error=""` before it resumes draining any backlog still left in the queue.
|
||||
- The exact behavior of late log attempts after closure is runtime-dependent, so callers should use lifecycle helpers like `is_closed()` and `shutdown()` instead of assuming identical post-close enqueue semantics everywhere.
|
||||
- Queue overflow behavior depends on `AsyncOverflowPolicy`.
|
||||
|
||||
### How to Use
|
||||
@@ -70,6 +80,28 @@ In this example, the worker drains queued records in the background and `shutdow
|
||||
|
||||
And the logging call path stays queue-oriented rather than direct-sink oriented.
|
||||
|
||||
#### When Need A One-call Target Override On The Root Async Logger
|
||||
|
||||
When async code should keep one logger value but emit a single record under a different target:
|
||||
```moonbit
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="app.async.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `app.async.audit` only for that one call.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Shared Context On A Root Async Logger
|
||||
|
||||
When async code should attach stable metadata to later queued records:
|
||||
```moonbit
|
||||
let contextual = logger.with_context_fields([@bitlogger.field("service", "billing")])
|
||||
```
|
||||
|
||||
In this example, the returned value still has the visible type `AsyncLogger[S]`.
|
||||
|
||||
And that shape preservation is intentional because async context binding updates stored logger metadata instead of changing the exposed sink type.
|
||||
|
||||
#### When Need Configurable Overflow And Flush Behavior
|
||||
|
||||
When queue semantics matter for service durability and load:
|
||||
@@ -103,3 +135,7 @@ e.g.:
|
||||
3. Example entrypoint limitations such as `async fn main` support are separate from the library-level portability of this API.
|
||||
|
||||
4. See [target-verification.md](./target-verification.md) for the current local verification matrix.
|
||||
|
||||
5. Pair this constructor with `run()` and `shutdown()` when you need the full worker lifecycle rather than just a configured async logger value.
|
||||
|
||||
6. Choose the facade name based on boundary intent: use `AsyncLogger[S]` for the full surface, `ApplicationAsyncLogger` or `ApplicationTextAsyncLogger` for application-facing alias names, and `LibraryAsyncLogger[S]` when a package boundary should intentionally narrow what downstream code can call directly.
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
name: async-overflow-policy
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public overflow policy alias used by AsyncLoggerConfig, async parser labels, and runtime queue behavior.
|
||||
key-word:
|
||||
- async
|
||||
- overflow
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-overflow-policy
|
||||
|
||||
`AsyncOverflowPolicy` is the public enum that controls what an `AsyncLogger` should do when its queue cannot accept a record immediately. It is a direct alias to the async model enum used by `AsyncLoggerConfig` and the runtime queue selection logic.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type AsyncOverflowPolicy = @utils.AsyncOverflowPolicy
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncOverflowPolicy` - Public async queue overflow enum with the variants `Blocking`, `DropOldest`, and `DropNewest`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a separate runtime adapter.
|
||||
- `AsyncOverflowPolicy::Blocking` waits for queue space when a non-blocking enqueue does not succeed.
|
||||
- `AsyncOverflowPolicy::DropOldest` lets the underlying async queue discard older pending records when capacity is limited.
|
||||
- `AsyncOverflowPolicy::DropNewest` discards the incoming record instead of blocking.
|
||||
- The same enum is used by `AsyncLoggerConfig::new(...)`, async config parsing, and the queue-kind mapping inside `AsyncLogger`.
|
||||
- The canonical labels `Blocking`, `DropOldest`, and `DropNewest` are also the labels emitted again by async config serializers, so export and parse stay aligned around one public vocabulary.
|
||||
- Async config parsing accepts the canonical label `DropNewest` and also the compatibility alias `DropLatest`, both mapping to the same public enum variant.
|
||||
- When `try_put(...)` reports that a record was not accepted under a drop policy, `dropped_count()` increases for that rejected enqueue.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need Backpressure Instead Of Silent Dropping
|
||||
|
||||
When producers should wait for queue space:
|
||||
```moonbit
|
||||
let config = AsyncLoggerConfig::new(max_pending=64, overflow=AsyncOverflowPolicy::Blocking)
|
||||
```
|
||||
|
||||
In this example, logging pressure can slow producers instead of dropping data immediately.
|
||||
|
||||
#### When Need Bounded Async Logging With Drop Behavior
|
||||
|
||||
When async logging should keep moving under load without blocking callers:
|
||||
```moonbit
|
||||
let config = AsyncLoggerConfig::new(max_pending=64, overflow=AsyncOverflowPolicy::DropNewest)
|
||||
```
|
||||
|
||||
In this example, the incoming record is dropped if the queue cannot accept it.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If async config text uses unsupported overflow text, async config parsing raises a failure.
|
||||
|
||||
- The parser error path for unsupported overflow text is the same `Failure` surface used by the async config utilities.
|
||||
|
||||
- Under drop policies, sustained overload increases `dropped_count()` instead of guaranteeing delivery.
|
||||
|
||||
- The precise record discarded by the underlying queue behavior depends on the selected policy and queue implementation, so callers should not assume `dropped_count()` alone identifies which message was lost.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This policy applies to `bitlogger_async`, not synchronous `QueuedSink`.
|
||||
|
||||
2. Choose `Blocking` only when producer-side waiting is acceptable for the caller.
|
||||
|
||||
3. Serialized config uses the canonical `DropNewest` label even though the parser also accepts `DropLatest`.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-runtime-mode-label
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Convert AsyncRuntimeMode into a stable string label for logs, JSON, and diagnostics.
|
||||
update-time: 20260614
|
||||
description: Convert AsyncRuntimeMode into its canonical stable string label for logs, JSON, and diagnostics.
|
||||
key-word:
|
||||
- async
|
||||
- runtime
|
||||
@@ -36,7 +36,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
- The returned value is intended for diagnostics and stable output, not just debugging prints.
|
||||
- It keeps mode serialization logic in one place.
|
||||
- This helper is used by async runtime JSON helpers.
|
||||
- `async_runtime_state_to_json(...)` serializes the `mode` field through this helper, so runtime snapshots and direct label rendering share the same canonical text.
|
||||
- Labels are more stable for telemetry and docs than ad hoc manual matching at call sites.
|
||||
- The current canonical labels are exactly `native_worker` for `NativeWorker` and `compatibility` for `Compatibility`.
|
||||
- This helper is only a pure enum-to-string mapping. It does not inspect the active backend or verify that the supplied enum still matches the current runtime environment.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -65,5 +68,13 @@ In this example, code gets a stable string without duplicating enum matching log
|
||||
e.g.:
|
||||
- This API assumes a valid `AsyncRuntimeMode` input and does not expose a normal runtime error path.
|
||||
|
||||
- If callers need the current backend-derived mode rather than a previously stored enum value, they must call `async_runtime_mode()` first and then label that result.
|
||||
|
||||
- If callers need the whole runtime object rather than a string label, use `async_runtime_state()`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when mode values should be rendered as stable text instead of manual enum matching.
|
||||
|
||||
2. `async_runtime_state_to_json(...)` uses these exact labels when serializing runtime snapshots.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-runtime-mode
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read the current async runtime mode and distinguish native worker behavior from compatibility behavior.
|
||||
update-time: 20260614
|
||||
description: Read the current async runtime mode and distinguish native-worker behavior from compatibility behavior using the same mode contract exposed through async runtime snapshots.
|
||||
key-word:
|
||||
- async
|
||||
- runtime
|
||||
@@ -37,6 +37,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `NativeWorker` is the expected mode on native-style backends, while `Compatibility` is the expected mode on targets without native background-worker semantics.
|
||||
- `async_runtime_mode_label(...)` converts the enum into a stable string value.
|
||||
- `async_runtime_supports_background_worker()` is a narrower boolean probe built on the same idea.
|
||||
- `async_runtime_state()` packages this mode together with the current background-worker capability into one `AsyncRuntimeState` snapshot.
|
||||
- In the current backend implementations, `NativeWorker` pairs with `background_worker=true` and `Compatibility` pairs with `background_worker=false`.
|
||||
- Concretely, the native runtime entrypoint returns `native_worker_async_runtime_mode()`, while the compatibility stub returns `compatibility_async_runtime_mode()`.
|
||||
- The enum is therefore selected directly by the active backend helper on each call rather than read back out of a cached runtime snapshot object.
|
||||
- This API is intentionally small and useful for lightweight branching.
|
||||
- The mode result describes runtime behavior only; it should not be read as proof that every backend has been equally re-verified in the current release cycle.
|
||||
|
||||
@@ -70,6 +74,8 @@ In this example, the output becomes a stable string instead of an enum pattern-m
|
||||
e.g.:
|
||||
- This API does not have a normal runtime failure mode; it reflects the compiled backend behavior.
|
||||
|
||||
- If callers need the current mode paired with the matching worker-support flag, prefer a fresh `async_runtime_state()` call instead of combining `async_runtime_mode()` with an older saved runtime snapshot.
|
||||
|
||||
- If you need worker support as a direct boolean, use `async_runtime_supports_background_worker()` instead.
|
||||
|
||||
### Notes
|
||||
@@ -78,6 +84,8 @@ e.g.:
|
||||
|
||||
2. Use `async_runtime_state()` when you also want worker support packaged into one object.
|
||||
|
||||
3. This mode distinction is about runtime behavior, not whether `src-async` itself is expected to compile for the target.
|
||||
3. Use `async_runtime_mode_label(...)` when the result should leave enum space and become stable text such as `native_worker` or `compatibility`.
|
||||
|
||||
4. See [target-verification.md](./target-verification.md) for the current verification status of individual targets.
|
||||
4. This mode distinction is about runtime behavior, not whether `src-async` itself is expected to compile for the target.
|
||||
|
||||
5. See [target-verification.md](./target-verification.md) for the current verification status of individual targets.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: async-runtime-state-new
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Construct an AsyncRuntimeState snapshot from explicit runtime mode and worker-support values without probing or validating the live backend.
|
||||
key-word:
|
||||
- async
|
||||
- runtime
|
||||
- state
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-runtime-state-new
|
||||
|
||||
Construct an `AsyncRuntimeState` snapshot from explicit runtime mode and worker-support values. This is the low-level constructor behind the public async runtime state shape used in diagnostics.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub fn AsyncRuntimeState::new(
|
||||
mode : AsyncRuntimeMode,
|
||||
background_worker : Bool,
|
||||
) -> AsyncRuntimeState {
|
||||
```
|
||||
|
||||
#### input
|
||||
|
||||
- `mode : AsyncRuntimeMode` - Backend-specific async runtime mode such as `NativeWorker` or `Compatibility`.
|
||||
- `background_worker : Bool` - Whether native-style background-worker support is available.
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncRuntimeState` - Runtime state snapshot containing the supplied mode and worker-support flag.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This constructor simply packages `mode` and `background_worker` into one public snapshot value.
|
||||
- It does not query the current backend automatically.
|
||||
- `async_runtime_state()` is the higher-level API that reads these values from the live runtime environment.
|
||||
- It also does not validate whether the supplied pair matches the current backend contract.
|
||||
- The supplied `mode` and `background_worker` values are stored exactly as provided; this constructor does not recompute, normalize, or cross-check either field.
|
||||
- The constructed value matches the same public shape used by async runtime serializers.
|
||||
- Because `AsyncRuntimeState` is only a data snapshot type, this constructor is mainly useful for tests, adapters, and synthetic diagnostics rather than ordinary runtime probing.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Hand-built Runtime Snapshot
|
||||
|
||||
When tests or adapters should construct a runtime state explicitly:
|
||||
```moonbit
|
||||
let runtime = AsyncRuntimeState::new(
|
||||
AsyncRuntimeMode::Compatibility,
|
||||
false,
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the runtime snapshot is built directly without probing the active backend.
|
||||
|
||||
#### When Need Structured Runtime Diagnostics Input
|
||||
|
||||
When code should prepare a runtime state value before serialization:
|
||||
```moonbit
|
||||
let runtime = AsyncRuntimeState::new(async_runtime_mode(), async_runtime_supports_background_worker())
|
||||
```
|
||||
In this example, callers still use the direct constructor while keeping the data source explicit.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- This constructor itself does not have a normal failure mode; it only packages the provided values.
|
||||
|
||||
- If callers want the current backend snapshot directly, `async_runtime_state()` is the simpler API.
|
||||
|
||||
- If callers manually pair `NativeWorker` with `false` or `Compatibility` with `true`, the constructor still accepts that snapshot because it does not enforce backend consistency.
|
||||
|
||||
- If callers want the currently probed runtime pair instead of a synthetic one, they must pass `async_runtime_mode()` plus `async_runtime_supports_background_worker()` explicitly or use `async_runtime_state()`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when code should construct an `AsyncRuntimeState` value explicitly.
|
||||
|
||||
2. Pair it with `AsyncLoggerState::new(...)` when assembling a full async logger snapshot by hand.
|
||||
|
||||
3. Prefer `async_runtime_state()` when the goal is to report the actual current backend pair rather than an arbitrary constructed snapshot.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-runtime-state-to-json
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Convert AsyncRuntimeState into a JSON value for runtime capability and mode diagnostics.
|
||||
update-time: 20260614
|
||||
description: Convert AsyncRuntimeState into a JSON value for runtime capability and mode diagnostics using the canonical mode labels and snapshot field names.
|
||||
key-word:
|
||||
- async
|
||||
- state
|
||||
@@ -35,8 +35,11 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The output includes `mode` and `background_worker`.
|
||||
- `mode` is serialized through `async_runtime_mode_label(...)`.
|
||||
- The compact serialized shape is `{"mode":"native_worker|compatibility","background_worker":true|false}`.
|
||||
- This helper focuses on runtime capabilities rather than queue counters or logger lifecycle flags.
|
||||
- The exported JSON is suitable for diagnostics endpoints and startup environment checks.
|
||||
- This helper serializes the provided `AsyncRuntimeState` exactly as given; it does not call `async_runtime_state()` or recheck backend capability by itself.
|
||||
- That means manually constructed runtime snapshots are exported unchanged, with `mode` relabeled through `async_runtime_mode_label(...)` and `background_worker` kept exactly as supplied.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -67,3 +70,11 @@ e.g.:
|
||||
|
||||
- If the runtime is in compatibility mode, the helper still serializes normally using the matching mode label.
|
||||
|
||||
- If callers need the current backend-derived runtime rather than an older or synthetic snapshot, they must capture a fresh `async_runtime_state()` first.
|
||||
|
||||
### Notes
|
||||
|
||||
1. The output field names are fixed as `mode` and `background_worker`.
|
||||
|
||||
2. The `mode` field always uses the canonical labels from `async_runtime_mode_label(...)`, not enum names like `NativeWorker` or `Compatibility`.
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: async-runtime-state-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public async runtime state alias used for backend capability snapshots and diagnostics, pairing runtime mode with background-worker support.
|
||||
key-word:
|
||||
- async
|
||||
- runtime
|
||||
- state
|
||||
- public
|
||||
---
|
||||
|
||||
## Async-runtime-state-type
|
||||
|
||||
`AsyncRuntimeState` is the public snapshot type used to describe backend-level async runtime capability. It is a direct alias to the async runtime state model returned by `async_runtime_state()` and used by async diagnostics serializers.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type AsyncRuntimeState = @utils.AsyncRuntimeState
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncRuntimeState` - Public runtime snapshot containing `mode` and `background_worker`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a live runtime controller.
|
||||
- The current fields are `mode : AsyncRuntimeMode` and `background_worker : Bool`.
|
||||
- `async_runtime_state()` returns this type directly as an environment-level snapshot.
|
||||
- `async_runtime_state()` currently builds that snapshot from `async_runtime_mode()` and `async_runtime_supports_background_worker()`.
|
||||
- `async_runtime_state_to_json(...)` and `stringify_async_runtime_state(...)` serialize the same snapshot shape for diagnostics.
|
||||
- `AsyncRuntimeState::new(...)` can also construct this type manually, but manual construction is synthetic data and does not probe the current backend by itself.
|
||||
- The type itself does not distinguish live backend snapshots from hand-built ones; callers must track whether a given `AsyncRuntimeState` value came from `async_runtime_state()` or from manual construction.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Typed Backend Capability Snapshot
|
||||
|
||||
When startup or diagnostics code should keep the runtime state as structured data:
|
||||
```moonbit
|
||||
let runtime : AsyncRuntimeState = async_runtime_state()
|
||||
```
|
||||
|
||||
In this example, the backend capability snapshot stays available as a typed value instead of only as printed text.
|
||||
|
||||
#### When Need To Read Runtime Mode And Worker Support Together
|
||||
|
||||
When code should inspect both async mode and worker availability from one object:
|
||||
```moonbit
|
||||
let runtime = async_runtime_state()
|
||||
if runtime.background_worker {
|
||||
println(async_runtime_mode_label(runtime.mode))
|
||||
}
|
||||
```
|
||||
|
||||
In this example, both fields are consumed from the same public snapshot type.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `AsyncRuntimeState` itself does not have a runtime failure mode.
|
||||
|
||||
- The snapshot is point-in-time diagnostic data; it should not be treated as proof that every target was re-verified in the current release cycle.
|
||||
|
||||
- Because this is just a data shape, manual construction can represent combinations that do not come from the current backend probe.
|
||||
|
||||
- Receiving an `AsyncRuntimeState` value alone does not prove it came from the current backend rather than from a synthetic constructor path.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `async_runtime_state()` when you need a value of this type from the current backend.
|
||||
|
||||
2. Use `AsyncLoggerState` when logger-instance queue and lifecycle information is also required.
|
||||
|
||||
3. Use `async_runtime_mode_label(...)` when the `mode` field should be rendered as stable text such as `native_worker` or `compatibility`.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-runtime-state
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Read the current backend-specific async runtime mode and worker capability.
|
||||
update-time: 20260614
|
||||
description: Read the current backend-specific async runtime snapshot as the paired result of runtime mode and background-worker capability.
|
||||
key-word:
|
||||
- async
|
||||
- runtime
|
||||
@@ -35,8 +35,12 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `mode` is derived from the active backend implementation.
|
||||
- `background_worker` tells callers whether native worker semantics are available.
|
||||
- This helper is equivalent to `AsyncRuntimeState::new(async_runtime_mode(), async_runtime_supports_background_worker())`.
|
||||
- The returned pair is rebuilt from those two lower-level helpers on each call rather than read from a cached runtime object.
|
||||
- In the current backend implementations, the resulting pair is `NativeWorker + true` or `Compatibility + false`.
|
||||
- `async_runtime_state_to_json(...)` and `stringify_async_runtime_state(...)` serialize this state.
|
||||
- This API is environment-scoped and does not depend on a particular `AsyncLogger` instance.
|
||||
- The returned value is a snapshot data object, not a live runtime handle, so later backend checks require calling `async_runtime_state()` again rather than reusing an older value as if it refreshed itself.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -68,6 +72,8 @@ In this example, branch decisions are based on actual runtime capability instead
|
||||
e.g.:
|
||||
- This API does not normally expose a dynamic error path; it reports the currently compiled backend behavior.
|
||||
|
||||
- The returned `AsyncRuntimeState` value is not cached onto the helper. If callers need a newer backend read, they must call `async_runtime_state()` again instead of expecting an older value to refresh itself.
|
||||
|
||||
- If callers need richer runtime state, they should use `AsyncLogger::state()` on a logger instance instead.
|
||||
|
||||
### Notes
|
||||
@@ -75,3 +81,5 @@ e.g.:
|
||||
1. Use this API for environment-level diagnostics.
|
||||
|
||||
2. Use `AsyncLogger::state()` for logger-instance diagnostics.
|
||||
|
||||
3. Use `AsyncRuntimeState::new(...)` only when code or tests need to construct a manual snapshot instead of probing the current backend.
|
||||
|
||||
@@ -36,6 +36,8 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `true` indicates native worker capability.
|
||||
- `false` indicates compatibility-mode behavior.
|
||||
- This helper is derived from backend-specific async runtime implementation choice.
|
||||
- The boolean is read from the active backend helper on each call rather than from a cached runtime snapshot object.
|
||||
- In the current backend split, the native implementation returns `true` while the compatibility stub returns `false`, matching the same mode pair exposed through `async_runtime_mode()` and `async_runtime_state()`.
|
||||
- The async library still targets multiple backends even when this helper returns `false`.
|
||||
- Use it when an enum branch is unnecessary and a boolean capability check is enough.
|
||||
|
||||
@@ -68,6 +70,8 @@ In this example, a simple boolean can drive compact status output.
|
||||
e.g.:
|
||||
- This API does not normally fail at runtime; it reflects compiled backend behavior.
|
||||
|
||||
- If callers need the current paired mode and worker flag together, prefer a fresh `async_runtime_state()` call instead of mixing this boolean with an older saved mode value.
|
||||
|
||||
- If you need the exact mode name rather than a boolean, use `async_runtime_mode()` or `async_runtime_state()`.
|
||||
|
||||
### Notes
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: buffered-sink-flush
|
||||
group: api
|
||||
category: sink
|
||||
update-time: 20260613
|
||||
description: Flush buffered records from a BufferedSink into its wrapped sink.
|
||||
key-word:
|
||||
- sink
|
||||
- buffer
|
||||
- flush
|
||||
- public
|
||||
---
|
||||
|
||||
## Buffered-sink-flush
|
||||
|
||||
Flush buffered records from a `BufferedSink[S]` into its wrapped sink. This is the direct sink-level batching control API for simple synchronous buffering.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub fn[S : Sink] BufferedSink::flush(self : BufferedSink[S]) -> Unit {
|
||||
```
|
||||
|
||||
#### input
|
||||
|
||||
- `self : BufferedSink[S]` - Buffered sink whose pending records should be forwarded to the wrapped sink.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- If the buffer is empty, the method does nothing.
|
||||
- When buffered records exist, they are copied into a temporary `pending` array, the live buffer is cleared, and each record is then written to the wrapped sink in order.
|
||||
- This helper drains only the local buffer; any later behavior still depends on the wrapped sink `S`.
|
||||
- The method does not return a count or success flag.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need Explicit Batch Delivery
|
||||
|
||||
When a buffered sink should forward pending records before the threshold is reached:
|
||||
```moonbit
|
||||
sink.flush()
|
||||
```
|
||||
|
||||
In this example, callers force buffered records to be written to the wrapped sink immediately.
|
||||
|
||||
#### When Need A Manual Flush Barrier
|
||||
|
||||
When tests or synchronous code want buffering but still need a deliberate release point:
|
||||
```moonbit
|
||||
let sink = buffered_sink(console_sink(), flush_limit=4)
|
||||
sink.flush()
|
||||
```
|
||||
|
||||
In this example, the buffered sink exposes a direct batching barrier without using queue semantics.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the wrapped sink's write behavior fails or has side effects, this helper does not add an extra reporting layer on top of `S`.
|
||||
|
||||
- If callers need a count-returning drain API with drop tracking, `QueuedSink::flush()` or `QueuedSink::drain()` may fit better.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper when code owns a `BufferedSink` directly and wants explicit control over when buffered records are forwarded.
|
||||
|
||||
2. Automatic flush still happens when buffered record count reaches `flush_limit` during writes.
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
name: buffered-sink-pending-count
|
||||
group: api
|
||||
category: sink
|
||||
update-time: 20260613
|
||||
description: Read the current buffered-record count from a BufferedSink.
|
||||
key-word:
|
||||
- sink
|
||||
- buffer
|
||||
- queue
|
||||
- public
|
||||
---
|
||||
|
||||
## Buffered-sink-pending-count
|
||||
|
||||
Read the current buffered-record count from a `BufferedSink[S]`. This is the direct sink-level metric for how many records are still waiting in the in-memory buffer.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub fn[S] BufferedSink::pending_count(self : BufferedSink[S]) -> Int {
|
||||
```
|
||||
|
||||
#### input
|
||||
|
||||
- `self : BufferedSink[S]` - Buffered sink whose current in-memory backlog should be inspected.
|
||||
|
||||
#### output
|
||||
|
||||
- `Int` - Current number of buffered records.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The return value is `self.buffer.val.length()` at the time of the call.
|
||||
- This is a point-in-time metric and may change immediately after it is read.
|
||||
- It reflects buffered records that have not yet been flushed to the wrapped sink.
|
||||
- This helper does not mutate the sink.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need Direct Buffer Backlog Visibility
|
||||
|
||||
When code is working with a `BufferedSink` value directly and wants to observe pending buffered records:
|
||||
```moonbit
|
||||
let pending = sink.pending_count()
|
||||
```
|
||||
|
||||
In this example, callers can inspect the current in-memory backlog without touching the wrapped sink.
|
||||
|
||||
#### When Verify Manual Flush Progress
|
||||
|
||||
When explicit flush steps should be checked operationally:
|
||||
```moonbit
|
||||
ignore(sink.flush())
|
||||
ignore(sink.pending_count())
|
||||
```
|
||||
|
||||
In this example, the metric helps verify whether buffered records were forwarded out of the local buffer.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- This helper does not have a normal failure mode; it only reads current buffer length.
|
||||
|
||||
- If callers need overflow-aware backlog semantics instead of simple buffering, `QueuedSink::pending_count()` is the better API.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use this helper for direct visibility into simple synchronous buffering.
|
||||
|
||||
2. Pair it with `flush()` when inspecting whether batched writes have been forwarded.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
name: buffered-sink-type
|
||||
group: api
|
||||
category: sink
|
||||
update-time: 20260613
|
||||
description: Public buffered sink type used for threshold-based synchronous batching over another sink.
|
||||
key-word:
|
||||
- sink
|
||||
- buffer
|
||||
- type
|
||||
- public
|
||||
---
|
||||
|
||||
## Buffered-sink-type
|
||||
|
||||
`BufferedSink[S]` is the public buffering sink type used for threshold-based synchronous batching over another sink. It is the concrete sink type returned by `buffered_sink(...)` and preserves the wrapped sink type in its type parameter.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub struct BufferedSink[S] {
|
||||
sink : S
|
||||
buffer : Ref[Array[Record]]
|
||||
flush_limit : Int
|
||||
}
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `BufferedSink[S]` - Public synchronous sink type that buffers records before forwarding them to the wrapped sink.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a public root struct, not a type alias.
|
||||
- The current fields are `sink : S`, `buffer : Ref[Array[Record]]`, and `flush_limit : Int`.
|
||||
- `buffered_sink(...)` constructs this type directly from a wrapped sink and flush threshold.
|
||||
- The sink preserves the wrapped sink type `S`, which is useful when typed composition still matters after buffering is introduced.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Typed Buffered Sink Value
|
||||
|
||||
When code should keep the concrete buffering sink type visible:
|
||||
```moonbit
|
||||
let sink : BufferedSink[ConsoleSink] = buffered_sink(console_sink(), flush_limit=2)
|
||||
```
|
||||
|
||||
In this example, the sink value stays explicit and preserves the wrapped console sink type.
|
||||
|
||||
#### When Need A Typed Logger With Synchronous Batching
|
||||
|
||||
When logging should preserve the buffering sink type in the logger:
|
||||
```moonbit
|
||||
let logger : Logger[BufferedSink[ConsoleSink]] = Logger::new(
|
||||
buffered_sink(console_sink(), flush_limit=2),
|
||||
target="buffered",
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the concrete buffered sink remains part of the logger type.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `BufferedSink[S]` itself does not have a runtime failure mode.
|
||||
|
||||
- Runtime behavior still depends on the wrapped sink `S`, and buffered records can remain pending if flushing never happens.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `buffered_sink(...)` when you need a value of this type.
|
||||
|
||||
2. Use `QueuedSink[S]` when overflow-aware queueing behavior is needed instead of simple buffering.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-application-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260520
|
||||
description: Build the application-facing async logger facade from an AsyncLoggerBuildConfig.
|
||||
update-time: 20260614
|
||||
description: Build the application-facing runtime-sink async logger alias from an AsyncLoggerBuildConfig through the sync-first async builder path.
|
||||
key-word:
|
||||
- application
|
||||
- async
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Build-application-async-logger
|
||||
|
||||
Build an `ApplicationAsyncLogger` from `AsyncLoggerBuildConfig`. This is the application-facing async facade over `build_async_logger(...)`.
|
||||
Build an `ApplicationAsyncLogger` from `AsyncLoggerBuildConfig`. This is the application-facing runtime-sink async alias returned through `build_async_logger(...)`.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -35,9 +35,19 @@ pub fn build_application_async_logger(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This API delegates to `build_async_logger(...)`.
|
||||
- The returned logger keeps the standard async lifecycle and state helper surface.
|
||||
- Use this facade when application code wants a dedicated async app-level entry point.
|
||||
- This API delegates to `build_async_logger(...)` directly.
|
||||
- That means the embedded `LoggerConfig` is built first through the normal synchronous config path before the outer async layer is applied.
|
||||
- Any optional synchronous queue layer and runtime-sink controls chosen by `build_logger(config.logger)` remain active under the returned logger.
|
||||
- In particular, a sync queue configured on `LoggerConfig.queue` is preserved inside the wrapped `RuntimeSink` variant instead of being stripped away by the application alias.
|
||||
- Because the result is only the `ApplicationAsyncLogger` alias over `AsyncLogger[@bitlogger.RuntimeSink]`, this builder does not hide any async helpers or introduce a wrapper layer.
|
||||
- The broader async helper surface is therefore preserved and directly exposed on the returned alias rather than being rebuilt or hidden behind an unwrap step.
|
||||
- The returned alias also keeps inherited async logger target behavior such as `with_target(...)`, `child(...)`, and per-call `target=` overrides on `log(...)`.
|
||||
- The returned logger keeps the full async lifecycle and state helper surface directly, including helpers such as `run()`, `shutdown()`, `pending_count()`, `dropped_count()`, `state()`, `wait_idle()`, `has_failed()`, and `last_error()`.
|
||||
- It also keeps the same queue counters, failure state, sink shape, and runtime-dependent post-close behavior as the underlying runtime-sink async logger.
|
||||
- Because this facade delegates to `build_async_logger(...)`, `Batch` and `Shutdown` also keep the underlying runtime-sink flush wiring: the returned alias uses the built sink's real `flush()` path instead of the default no-op callback used by the text-specific builder line.
|
||||
- In the current direct builder coverage, this alias matches `build_async_logger(config)` all the way through serialized state snapshots, runtime-sink variant choice, queue counters, lifecycle flags, and later failure fields after `run()` or `shutdown()`.
|
||||
- File-backed runtime helpers on the returned `RuntimeSink` also stay aligned with the direct builder result instead of being hidden behind a separate application-layer wrapper.
|
||||
- Use this alias-oriented builder when application code wants the standard runtime-sink async shape without narrowing the public surface.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -57,6 +67,23 @@ let logger = build_application_async_logger(
|
||||
|
||||
In this example, the app-facing async facade is built directly from typed config.
|
||||
|
||||
And any configured synchronous runtime sink controls remain available through the returned `RuntimeSink`-backed async logger.
|
||||
|
||||
And unlike `build_library_async_logger(...)`, no `to_async_logger()` unwrap is required to reach queue, lifecycle, or file-backed runtime helpers.
|
||||
|
||||
The returned value also keeps the ordinary async logger target semantics because the facade does not wrap or narrow the underlying `AsyncLogger[@bitlogger.RuntimeSink]`.
|
||||
|
||||
#### When Need Async State Helpers Immediately After App Construction
|
||||
|
||||
When application code should keep the ordinary async helper surface directly:
|
||||
```moonbit
|
||||
let logger = build_application_async_logger(config)
|
||||
ignore(logger.pending_count())
|
||||
ignore(logger.state())
|
||||
```
|
||||
|
||||
In this example, the application alias exposes async state helpers directly because no narrowing wrapper is added.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -64,8 +91,16 @@ e.g.:
|
||||
|
||||
- If the logger is never `run()`, enqueue behavior and lifecycle state still follow the normal async logger rules.
|
||||
|
||||
- If callers rely on file-backed runtime helpers, they should treat this builder as the same runtime-sink result as `build_async_logger(config)`, not as a reduced alias with different helper behavior.
|
||||
|
||||
- If callers specifically want the text-console async path where `Batch` and `Shutdown` keep the default no-op flush callback, `build_application_text_async_logger(...)` is the different contract; this runtime-sink alias preserves the real sink `flush()` behavior from `build_async_logger(...)`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This is a facade over the existing async runtime logger builder.
|
||||
|
||||
2. Use `parse_and_build_application_async_logger(...)` when starting from JSON text.
|
||||
|
||||
3. Use `build_application_text_async_logger(...)` instead when callers should keep the concrete text-console sink type and the direct text-builder path.
|
||||
|
||||
4. Use `build_library_async_logger(...)` instead when a library boundary should narrow the exposed async surface.
|
||||
|
||||
@@ -3,7 +3,7 @@ name: build-application-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260520
|
||||
description: Build the application-facing configured logger facade from a LoggerConfig.
|
||||
description: Build the application-facing configured logger alias from a LoggerConfig by delegating directly to the normal runtime logger build path.
|
||||
key-word:
|
||||
- application
|
||||
- facade
|
||||
@@ -33,9 +33,13 @@ pub fn build_application_logger(config : LoggerConfig) -> ApplicationLogger {
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This API delegates to `build_logger(...)`.
|
||||
- The returned value keeps the same public logging, queue, and file runtime helper surface as `ConfiguredLogger`.
|
||||
- Use this facade when application boot code wants an app-specific entry name without exposing lower-level builder naming in its own code.
|
||||
- This API delegates to `build_logger(...)` directly.
|
||||
- The embedded config still goes through the normal runtime logger build path, including runtime sink selection, optional queue wrapping, and timestamp application.
|
||||
- Because the result is only the `ApplicationLogger` alias over `ConfiguredLogger`, this builder does not hide any queue, drain, flush, or file runtime helper methods.
|
||||
- The configured runtime helper surface is therefore preserved and directly exposed on the returned alias rather than being rebuilt or hidden behind an unwrap step.
|
||||
- The returned alias also keeps inherited `Logger` behavior such as `with_target(...)`, `child(...)`, and per-call `target=` overrides on `log(...)`.
|
||||
- That means `log(..., target=...)` can override the target for one write, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue to use the stored logger target unless a derived logger was created first with `with_target(...)` or `child(...)`.
|
||||
- Use this alias-oriented entrypoint when application boot code wants an app-specific name without changing the underlying configured runtime logger surface.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -52,6 +56,24 @@ let logger = build_application_logger(
|
||||
|
||||
In this example, the application facade builds the same configured runtime logger shape as `build_logger(...)`.
|
||||
|
||||
And any queue/file/runtime helpers selected by the config remain directly available on the returned alias value.
|
||||
|
||||
And unlike `build_library_logger(...)`, no `to_logger()` unwrap is required to reach that helper surface.
|
||||
|
||||
The returned value also keeps the ordinary logger target semantics because the facade does not wrap or narrow the underlying `ConfiguredLogger`.
|
||||
|
||||
#### When Need A Per-call Target Override After App-oriented Build
|
||||
|
||||
When typed app config should still build a logger that supports a one-write target override:
|
||||
```moonbit
|
||||
let logger = build_application_logger(config)
|
||||
logger.log(Level::Error, "boom", target="app.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `app.audit` for that write.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -64,3 +86,5 @@ e.g.:
|
||||
1. This is a facade API, not a separate runtime implementation.
|
||||
|
||||
2. Use `parse_and_build_application_logger(...)` when starting from JSON text.
|
||||
|
||||
3. Use `build_library_logger(...)` instead when the public surface should intentionally hide configured-runtime helper methods.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-application-text-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260520
|
||||
description: Build the application-facing text-console async logger facade from an AsyncLoggerBuildConfig.
|
||||
update-time: 20260614
|
||||
description: Build the application-facing text-console async logger alias from an AsyncLoggerBuildConfig using the direct concrete text-sink builder path.
|
||||
key-word:
|
||||
- application
|
||||
- async
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Build-application-text-async-logger
|
||||
|
||||
Build an `ApplicationTextAsyncLogger` from `AsyncLoggerBuildConfig`. This facade is the application-oriented async builder for the text-console runtime sink shape returned by `build_async_text_logger(...)`.
|
||||
Build an `ApplicationTextAsyncLogger` from `AsyncLoggerBuildConfig`. This is the application-oriented async alias builder for the concrete text-console sink shape returned by `build_async_text_logger(...)`.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -35,9 +35,22 @@ pub fn build_application_text_async_logger(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This API delegates to `build_async_text_logger(...)`.
|
||||
- This API delegates to `build_async_text_logger(...)` directly.
|
||||
- It is intended for config-driven async text console output where callers want the concrete text sink shape rather than the broader runtime sink enum wrapper.
|
||||
- The returned logger keeps the usual async lifecycle helpers.
|
||||
- The builder always creates a `FormattedConsoleSink` from `config.logger.sink.text_formatter` instead of selecting among sink kinds.
|
||||
- That means even if `config.logger.sink.kind` says `Console`, `JsonConsole`, or `File`, this facade still follows the text-console path and uses only the configured `text_formatter` details.
|
||||
- Unlike `build_application_async_logger(...)`, this alias-oriented builder does not go through the full synchronous configured-logger build path first.
|
||||
- It uses the selected text-oriented `LoggerConfig` fields directly and therefore does not apply `LoggerConfig.queue` or preserve sync runtime sink controls.
|
||||
- A sync queue configured on `LoggerConfig.queue` is therefore ignored by this builder instead of being preserved under the returned async logger.
|
||||
- Because the result is only the `ApplicationTextAsyncLogger` alias over `AsyncLogger[@bitlogger.FormattedConsoleSink]`, this builder returns the same underlying async logger value as `build_async_text_logger(...)` and does not hide any async helpers or introduce a wrapper layer.
|
||||
- The returned alias also keeps inherited async logger target behavior such as `with_target(...)`, `child(...)`, and per-call `target=` overrides on `log(...)`.
|
||||
- In particular, `log(..., target=...)` can override the target for one call, while severity helpers such as `debug(...)`, `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- The returned logger keeps the full async lifecycle and state helper surface directly, including helpers such as `run()`, `shutdown()`, `pending_count()`, `dropped_count()`, `state()`, `wait_idle()`, `has_failed()`, and `last_error()`.
|
||||
- It also keeps the same close, queue, and failure-state semantics as the underlying `AsyncLogger[@bitlogger.FormattedConsoleSink]`.
|
||||
- In the current direct text-builder coverage, this alias matches `build_async_text_logger(config)` through serialized state snapshots, formatter behavior, queue counters, lifecycle flags, and later failure fields after worker execution.
|
||||
- Its configured `flush_policy` is still visible on the returned alias, but this text-specific build path does not wire the explicit sink flush callback that `build_application_async_logger(...)` inherits through `build_async_logger(...)`.
|
||||
- That means `Batch` and `Shutdown` only drive the default no-op async flush callback here; they do not add an extra explicit sink flush step beyond ordinary `FormattedConsoleSink` writes.
|
||||
- Use `build_library_async_text_logger(...)` instead when the next boundary should keep the same concrete text sink type but intentionally narrow the directly exposed async helper surface.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -57,15 +70,50 @@ let logger = build_application_text_async_logger(
|
||||
|
||||
In this example, the async logger is built for text-console output specifically.
|
||||
|
||||
And the chosen builder path matters more than `config.logger.sink.kind`: this facade still uses the text formatter directly because it always builds a `FormattedConsoleSink`.
|
||||
|
||||
And the returned value keeps the ordinary async logger target semantics because this facade does not wrap or narrow the underlying `AsyncLogger[@bitlogger.FormattedConsoleSink]`.
|
||||
|
||||
#### When Need A Per-call Target Override After App Text Construction
|
||||
|
||||
When typed app async text config should still build a logger that supports a one-call target override:
|
||||
```moonbit
|
||||
let logger = build_application_text_async_logger(config)
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="app.text.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `app.text.audit` for that call.
|
||||
|
||||
And later `debug(...)`, `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Async State Helpers Immediately After Text App Construction
|
||||
|
||||
When application code should keep the ordinary async helper surface directly on the text-console variant:
|
||||
```moonbit
|
||||
let logger = build_application_text_async_logger(config)
|
||||
ignore(logger.pending_count())
|
||||
ignore(logger.state())
|
||||
```
|
||||
|
||||
In this example, the application text alias exposes async state helpers directly because no narrowing wrapper is added.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the embedded logger config selects a non-text sink shape, the caller should use the general async builder facade instead.
|
||||
- If callers need sink-kind-driven branching such as JSON console or file-backed async output, they should use `build_application_async_logger(...)` instead.
|
||||
|
||||
- If the config carries file-oriented fields such as `path` only because `sink.kind` was set to `File`, this facade still ignores that sink-kind choice and does not create a file-backed async logger.
|
||||
|
||||
- If runtime draining is never started, records still follow the normal async queue lifecycle rules.
|
||||
|
||||
- If callers rely on the formatter or state shape after text-builder construction, they should treat this as the same direct `build_async_text_logger(config)` result rather than a reduced alias with different helper behavior.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This is a narrower text-console async facade than `build_application_async_logger(...)`.
|
||||
|
||||
2. It is most useful when callers want the `FormattedConsoleSink`-backed async type explicitly.
|
||||
|
||||
3. Use `build_application_async_logger(...)` instead when callers need the broader runtime-sink build path, including sync queue application through `build_logger(config.logger)`.
|
||||
|
||||
4. Use `build_library_async_text_logger(...)` instead when the public boundary should narrow the exposed async surface while preserving the same concrete text sink type.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-async-logger
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260512
|
||||
description: Build an async logger from combined logger and async config without manually wiring the runtime sink.
|
||||
update-time: 20260614
|
||||
description: Build an async logger from combined logger and async config by first building the sync runtime logger and then wrapping its sink in the async layer.
|
||||
key-word:
|
||||
- async
|
||||
- config
|
||||
@@ -34,9 +34,18 @@ pub fn build_async_logger(config : AsyncLoggerBuildConfig) -> AsyncLogger[@bitlo
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The `logger` section is built through the same config machinery used by synchronous configured loggers.
|
||||
- That means `LoggerConfig.sink` and the optional synchronous `LoggerConfig.queue` are applied before the async layer is added.
|
||||
- The resulting async logger inherits `min_level`, `target`, and timestamp behavior from the built synchronous logger.
|
||||
- File, queue, and formatter choices all come from config rather than direct code-side sink wiring.
|
||||
- File, formatter, and any configured synchronous queue choices all come from config rather than direct code-side sink wiring.
|
||||
- The returned sink type is `RuntimeSink`, which keeps configured control helpers available where relevant.
|
||||
- This builder returns the underlying `AsyncLogger[@bitlogger.RuntimeSink]` value directly. `build_application_async_logger(...)` only re-exports the same result under the `ApplicationAsyncLogger` alias, while `build_library_async_logger(...)` wraps the same result in `LibraryAsyncLogger[@bitlogger.RuntimeSink]`.
|
||||
- The returned async logger also keeps ordinary target rules unchanged: `log(..., target=...)` can override the target for one call, while severity helpers such as `debug(...)`, `info(...)`, and `error(...)` continue to use the stored logger target unless a derived logger was created first with `with_target(...)` or `child(...)`.
|
||||
- Because this path starts from `build_logger(config.logger)`, it preserves the broader runtime-sink build path, including sync-side queue decoration when `LoggerConfig.queue` is present.
|
||||
- Because this path starts from `build_logger(config.logger)`, `config.logger.sink.kind` has already selected the concrete `RuntimeSink` variant before async wrapping, and optional sync queue decoration can further turn that built sink into queued runtime variants such as `QueuedConsole` or `QueuedFile`.
|
||||
- This runtime-sink path also wires the explicit async flush callback as `flush=fn(sink) { sink.flush() }`, so `Batch` and `Shutdown` policies invoke the built runtime sink's real flush behavior instead of the default no-op callback.
|
||||
- In the current direct builder coverage, the returned logger exposes the expected serialized async state snapshot, runtime-sink variant choice, queue counters, lifecycle flags, and later failure fields after `run()` or `shutdown()`.
|
||||
- File-backed runtime helpers also stay directly available on the returned `RuntimeSink` with the same behavior later observed through the application and library facade equivalence tests.
|
||||
- Use `build_async_text_logger(...)` instead when you want the direct text-console async builder path with `FormattedConsoleSink` and without the sync runtime-sink construction layer.
|
||||
- The `src-async` library is designed to compile on `native / llvm / js / wasm / wasm-gc`, but runtime mode differs by backend.
|
||||
- Current local release-facing verification is explicit for `native / js / wasm / wasm-gc`.
|
||||
- `llvm` remains experimental and did not complete local verification in this environment.
|
||||
@@ -60,6 +69,18 @@ In this example, parsing and async runtime wiring are separated cleanly.
|
||||
|
||||
And the returned logger can immediately be started with `run()`.
|
||||
|
||||
#### When Need A Per-call Target Override After Typed Async Build
|
||||
|
||||
When typed async config should still build a logger that supports a one-call target override:
|
||||
```moonbit
|
||||
let logger = build_async_logger(config)
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="svc.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `svc.audit` for that call.
|
||||
|
||||
And later `debug(...)`, `info(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Runtime Sink Features After Async Build
|
||||
|
||||
When the sink shape is configured but runtime features still matter:
|
||||
@@ -70,6 +91,10 @@ println(stringify_async_logger_state(logger.state(), pretty=true))
|
||||
|
||||
In this example, the built async logger remains introspectable even though construction was config-driven.
|
||||
|
||||
And any configured synchronous runtime sink controls are preserved inside the returned `RuntimeSink`.
|
||||
|
||||
And if `AsyncFlushPolicy::Batch` or `Shutdown` is configured, this builder uses the runtime sink's real `flush()` path rather than the default no-op callback used by the text-specific builder line.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
@@ -77,6 +102,12 @@ e.g.:
|
||||
|
||||
- If the configured sink shape is unsupported for a specific capability, the resulting runtime behavior follows the existing sink/runtime rules rather than inventing a separate builder-only failure model.
|
||||
|
||||
- If callers depend on queued runtime-sink helpers or file-backed runtime helpers, this builder is the direct API that preserves them rather than a reduced facade path.
|
||||
|
||||
- If callers depend on the exact runtime-sink variant, they should read this builder as preserving the sync-first sink selection result from `build_logger(config.logger)`, not as deferring sink-kind branching until after the async layer is added.
|
||||
|
||||
- If callers need the text-console path where `Batch` and `Shutdown` keep the default no-op flush callback, `build_async_text_logger(...)` is the different builder contract; this runtime-sink path intentionally wires the sink's real `flush()` behavior.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this API when applications externalize both sync sink choice and async queue behavior.
|
||||
@@ -86,3 +117,5 @@ e.g.:
|
||||
3. Library portability is broader than example portability: a runnable `async fn main` example may still be target-limited even when the async library itself compiles for that backend.
|
||||
|
||||
4. See [target-verification.md](./target-verification.md) for the current verification boundary.
|
||||
|
||||
5. If the next boundary is library-facing rather than application-facing, build here and then narrow with `build_library_async_logger(...)` instead of documenting the broader runtime helper surface directly.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-async-text-logger
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260520
|
||||
description: Build an async logger with a concrete text-console sink from combined logger and async config.
|
||||
update-time: 20260614
|
||||
description: Build an async logger with a concrete text-console sink from combined logger and async config, using only the selected text-oriented LoggerConfig fields instead of the full sync build path.
|
||||
key-word:
|
||||
- async
|
||||
- text
|
||||
@@ -34,7 +34,16 @@ pub fn build_async_text_logger(config : AsyncLoggerBuildConfig) -> AsyncLogger[@
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This builder converts `config.logger.sink.text_formatter` into a runtime `TextFormatter` and wires it into `text_console_sink(...)`.
|
||||
- It always constructs a `FormattedConsoleSink` directly instead of branching on `config.logger.sink.kind`.
|
||||
- That means even if `config.logger.sink.kind` says `Console`, `JsonConsole`, or `File`, this builder still follows the text-console path and uses only the configured `text_formatter` details.
|
||||
- The returned logger inherits `min_level`, `target`, and timestamp behavior from `config.logger`.
|
||||
- Unlike `build_async_logger(...)`, this helper does not run the full synchronous `build_logger(config.logger)` path first.
|
||||
- That means it uses `config.logger.sink.text_formatter`, `min_level`, `target`, and `timestamp` directly, but it does not apply `LoggerConfig.queue` or preserve other sync runtime sink controls.
|
||||
- This builder returns the underlying `AsyncLogger[@bitlogger.FormattedConsoleSink]` value directly. `build_application_text_async_logger(...)` only re-exports that same result under the `ApplicationTextAsyncLogger` alias, while `build_library_async_text_logger(...)` wraps the same result in `LibraryAsyncLogger[@bitlogger.FormattedConsoleSink]`.
|
||||
- The returned async logger also keeps ordinary target rules unchanged: `log(..., target=...)` can override the target for one call, while severity helpers such as `debug(...)`, `info(...)`, `warn(...)`, and `error(...)` continue to use the stored logger target unless a derived logger was created first with `with_target(...)` or `child(...)`.
|
||||
- In the current direct text-builder coverage, the returned logger exposes the expected serialized async state snapshot, formatter behavior, queue counters, lifecycle flags, and later failure fields after worker execution.
|
||||
- The async `flush_policy` still comes from `config.async_config`, but this text-specific builder does not supply the explicit `flush=fn(sink) { sink.flush() }` callback used by `build_async_logger(...)`.
|
||||
- In practice, `Batch` and `Shutdown` therefore only trigger the default no-op async flush callback on this path, while each record write still follows whatever immediate behavior `FormattedConsoleSink` already has on its own.
|
||||
- This helper is best suited to text-console output paths where callers want the concrete formatted sink type instead of `RuntimeSink`.
|
||||
- This async text path follows the same target story as the broader async library: `native / js / wasm / wasm-gc` have stronger local verification, while `llvm` remains experimental and locally unverified in this environment.
|
||||
|
||||
@@ -56,13 +65,31 @@ let logger = build_async_text_logger(
|
||||
|
||||
In this example, the async logger is built around a text console sink rather than the generic runtime sink enum.
|
||||
|
||||
And the chosen builder path matters more than `config.logger.sink.kind`: this helper still uses the text formatter directly because it always builds a `FormattedConsoleSink`.
|
||||
|
||||
#### When Need A Per-call Target Override After Built Async Text Construction
|
||||
|
||||
When typed async text config should still build a logger that supports a one-call target override:
|
||||
```moonbit
|
||||
let logger = build_async_text_logger(config)
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="async.text.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `async.text.audit` for that call.
|
||||
|
||||
And later `debug(...)`, `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the logger config was not intended for text-console style output, the broader `build_async_logger(...)` path may be a better fit.
|
||||
- If callers need sink-kind-driven branching across console, JSON, text, or file output, `build_async_logger(...)` is the better fit.
|
||||
|
||||
- If the config carries file-oriented fields such as `path` only because `sink.kind` was set to `File`, this builder still ignores that sink-kind choice and does not create a file-backed async logger.
|
||||
|
||||
- If the logger is never `run()`, pending records still follow the normal async queue lifecycle rules.
|
||||
|
||||
- If callers rely on the concrete formatter or post-run state shape, this builder is the direct API that preserves those text-console details rather than a reduced alias or wrapper.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This API is narrower than `build_async_logger(...)` because it preserves a concrete text sink type.
|
||||
@@ -70,3 +97,5 @@ e.g.:
|
||||
2. It is the base builder used by the application and library async text facades.
|
||||
|
||||
3. See [target-verification.md](./target-verification.md) for the current local verification matrix.
|
||||
|
||||
4. Use this direct builder when callers should keep the full async helper surface on the concrete text sink type rather than a naming alias or a narrowed library wrapper.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-library-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260520
|
||||
description: Build the library-facing async logger facade from an AsyncLoggerBuildConfig.
|
||||
update-time: 20260614
|
||||
description: Build the library-facing async logger facade from an AsyncLoggerBuildConfig while intentionally hiding direct async state helpers.
|
||||
key-word:
|
||||
- library
|
||||
- async
|
||||
@@ -35,9 +35,19 @@ pub fn build_library_async_logger(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This API builds the general async runtime logger and then wraps it in the narrower `LibraryAsyncLogger` facade.
|
||||
- This API builds the general async runtime logger and then wraps it in the narrower `LibraryAsyncLogger[@bitlogger.RuntimeSink]` facade.
|
||||
- The embedded `LoggerConfig` still goes through the normal synchronous config path first, so sink shape and any optional synchronous queue layer are already applied before the outer async layer is wrapped and then narrowed.
|
||||
- The returned facade wraps the same underlying `AsyncLogger[@bitlogger.RuntimeSink]` value that `build_async_logger(...)` would produce directly.
|
||||
- The result keeps async lifecycle operations such as `run()` and `shutdown()` while narrowing the public shape.
|
||||
- The broader async helper surface is preserved rather than rebuilt, but it is intentionally not directly exposed on the returned facade. Queue counters, lifecycle state, idle-wait helpers, and file-backed runtime helpers stay behind `to_async_logger()` instead of disappearing.
|
||||
- The narrower facade does not change the underlying runtime-sink queue counters, failure state, sink shape, or runtime-dependent post-close behavior; it only hides the broader helper surface until `to_async_logger()` is used.
|
||||
- Because this facade starts from `build_async_logger(...)`, the wrapped async logger also keeps the runtime-sink flush wiring: `Batch` and `Shutdown` use the built sink's real `flush()` path instead of the default no-op callback used by the text-specific builder line.
|
||||
- The facade still preserves the underlying async target rules on its exposed write methods: `log(..., target=...)` can override the target for one call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless the facade first derived another logger with `with_target(...)` or `child(...)`.
|
||||
- In the current direct builder coverage, unwrapping this facade produces the same async state snapshot, runtime-sink variant, queue counters, lifecycle flags, and failure fields as calling `build_async_logger(config)` directly.
|
||||
- That same unwrap also preserves file-backed runtime helpers on `RuntimeSink` values rather than replacing them with facade-specific behavior.
|
||||
- Async state helpers such as `pending_count()`, `dropped_count()`, `state()`, `wait_idle()`, and failure-status inspection remain on the underlying `AsyncLogger`, not on the returned facade itself.
|
||||
- `to_async_logger()` can be used to recover the underlying full async logger.
|
||||
- Use this builder when the boundary should preserve the runtime-sink async build path but still hide broader async inspection helpers from downstream callers.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -57,15 +67,46 @@ let logger = build_library_async_logger(
|
||||
|
||||
In this example, async runtime construction is hidden behind the library facade.
|
||||
|
||||
#### When Need Async State Helpers After Library-oriented Construction
|
||||
|
||||
When config-built async state inspection is still needed internally:
|
||||
```moonbit
|
||||
let logger = build_library_async_logger(config)
|
||||
let full = logger.to_async_logger()
|
||||
ignore(full.pending_count())
|
||||
```
|
||||
|
||||
In this example, the library async facade is unwrapped before using async state helpers.
|
||||
|
||||
And unlike `ApplicationAsyncLogger`, the narrower builder result does not expose those broader async helpers directly on the facade surface.
|
||||
|
||||
#### When Need A Per-call Target Override Through The Library Async Builder Facade
|
||||
|
||||
When typed library async config should still build a facade that allows a one-call target override without unwrapping first:
|
||||
```moonbit
|
||||
let logger = build_library_async_logger(config)
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="lib.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `lib.audit` for that call.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the facade's stored target unless code derives another facade first with `with_target(...)` or `child(...)`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If backend-specific sink limitations exist, they still apply under the facade.
|
||||
|
||||
- If callers need methods outside the library facade, they must unwrap with `to_async_logger()`.
|
||||
- If callers need async state, failure-status, or idle-wait helpers outside the library facade, they must unwrap with `to_async_logger()`.
|
||||
|
||||
- If callers need file-backed runtime helpers such as file-state or queued runtime inspection, they must unwrap first, but the helper behavior itself stays aligned with the direct `build_async_logger(config)` result.
|
||||
|
||||
- If callers instead want the text-console builder path where `Batch` and `Shutdown` keep the default no-op flush callback, they should use `build_library_async_text_logger(...)`; this runtime-sink facade preserves the real sink `flush()` behavior from `build_async_logger(...)`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this API when library boundaries should stay narrow.
|
||||
|
||||
2. Use `parse_and_build_library_async_logger(...)` when starting from JSON text.
|
||||
|
||||
3. Use `build_library_async_text_logger(...)` instead when the library-facing async type should preserve the narrower `FormattedConsoleSink` shape rather than `RuntimeSink`.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-library-async-text-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260520
|
||||
description: Build the library-facing text-console async logger facade from an AsyncLoggerBuildConfig.
|
||||
update-time: 20260614
|
||||
description: Build the library-facing text-console async logger facade from an AsyncLoggerBuildConfig using the concrete text-console builder path.
|
||||
key-word:
|
||||
- library
|
||||
- async
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Build-library-async-text-logger
|
||||
|
||||
Build a `LibraryAsyncLogger[FormattedConsoleSink]` from `AsyncLoggerBuildConfig`. This facade is the library-oriented async builder for text-console runtime output.
|
||||
Build a `LibraryAsyncLogger[FormattedConsoleSink]` from `AsyncLoggerBuildConfig`. This facade is the library-oriented async builder for the concrete text-console sink shape returned by `build_async_text_logger(...)`.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -35,9 +35,20 @@ pub fn build_library_async_text_logger(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This API delegates to `build_async_text_logger(...)` and then wraps the result as `LibraryAsyncLogger`.
|
||||
- It is useful when library code wants a narrow async facade while preserving a concrete text-console sink type.
|
||||
- This API delegates to `build_async_text_logger(...)` and then narrows the result to `LibraryAsyncLogger[@bitlogger.FormattedConsoleSink]`.
|
||||
- It always produces a concrete `FormattedConsoleSink` from `config.logger.sink.text_formatter` instead of branching on sink kinds.
|
||||
- That means even if `config.logger.sink.kind` says `Console`, `JsonConsole`, or `File`, this facade still follows the text-console path and uses only the configured `text_formatter` details.
|
||||
- Unlike `build_library_async_logger(...)`, this facade does not go through the full synchronous configured-logger build path first.
|
||||
- It uses the selected text-oriented `LoggerConfig` fields directly and therefore does not apply `LoggerConfig.queue` or preserve sync runtime sink controls.
|
||||
- A sync queue configured on `LoggerConfig.queue` is therefore ignored by this builder instead of being preserved behind the wrapped text-console async logger.
|
||||
- The returned facade wraps the same underlying `AsyncLogger[@bitlogger.FormattedConsoleSink]` value that `build_async_text_logger(...)` would return directly, so `run()`, `shutdown()`, and queue or failure-state behavior are unchanged under the narrower public type.
|
||||
- In the current direct text-builder coverage, unwrapping this facade yields the same async state snapshot, formatter behavior, queue counters, lifecycle flags, and later failure fields as calling `build_async_text_logger(config)` directly.
|
||||
- The configured `flush_policy` is still carried by that underlying async logger, but this text-specific builder path does not provide the explicit sink flush callback used by `build_library_async_logger(...)` through `build_async_logger(...)`.
|
||||
- As a result, `Batch` and `Shutdown` only invoke the default no-op async flush callback on this text-console path unless downstream code unwraps and adds different behavior elsewhere.
|
||||
- The facade still preserves the underlying async target rules on its exposed write methods: `log(..., target=...)` can override the target for one call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless the facade first derived another logger with `with_target(...)` or `child(...)`.
|
||||
- Async state helpers such as `pending_count()`, `dropped_count()`, `state()`, `wait_idle()`, and failure-status inspection remain on the underlying `AsyncLogger[@bitlogger.FormattedConsoleSink]`, not on the returned facade itself.
|
||||
- `to_async_logger()` can recover the underlying full async logger if needed.
|
||||
- Use this builder when the boundary should preserve the concrete text-console sink type while still hiding broader async inspection and helper APIs from downstream callers.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -57,10 +68,41 @@ let logger = build_library_async_text_logger(
|
||||
|
||||
In this example, the async text sink shape is preserved under the library facade.
|
||||
|
||||
And the chosen builder path matters more than `config.logger.sink.kind`: this facade still uses the text formatter directly because it always builds a `FormattedConsoleSink` before narrowing to `LibraryAsyncLogger[@bitlogger.FormattedConsoleSink]`.
|
||||
|
||||
#### When Need Async State Helpers After Library Text Construction
|
||||
|
||||
When library-facing text-console construction should still allow internal async inspection later:
|
||||
```moonbit
|
||||
let logger = build_library_async_text_logger(config)
|
||||
let full = logger.to_async_logger()
|
||||
ignore(full.pending_count())
|
||||
```
|
||||
|
||||
In this example, the facade is unwrapped before using async state helpers.
|
||||
|
||||
#### When Need A Per-call Target Override Through The Library Async Text Builder Facade
|
||||
|
||||
When typed library async text config should still build a facade that allows a one-call target override without unwrapping first:
|
||||
```moonbit
|
||||
let logger = build_library_async_text_logger(config)
|
||||
logger.log(@bitlogger.Level::Error, "boom", target="lib.text.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `lib.text.audit` for that call.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the facade's stored target unless code derives another facade first with `with_target(...)` or `child(...)`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the embedded logger config does not describe text-console output, the caller should use the broader async facade instead.
|
||||
- If callers need sink-kind-driven branching such as JSON console or file-backed async output, they should use `build_library_async_logger(...)` instead.
|
||||
|
||||
- If the config carries file-oriented fields such as `path` only because `sink.kind` was set to `File`, this facade still ignores that sink-kind choice and does not create a file-backed async logger.
|
||||
|
||||
- If callers expect async state or idle-wait helpers directly on the returned facade, they must unwrap first with `to_async_logger()`.
|
||||
|
||||
- If callers need to inspect the actual formatter-backed async state after library-level `run()` or `shutdown()` calls, unwrapping exposes the same post-call counters and failure fields that the direct text builder would have produced.
|
||||
|
||||
- Normal async lifecycle expectations still apply if the logger is never run.
|
||||
|
||||
@@ -69,3 +111,5 @@ e.g.:
|
||||
1. This is the library-side counterpart to `build_application_text_async_logger(...)`.
|
||||
|
||||
2. It is most useful when a concrete text-console async sink type matters to the caller boundary.
|
||||
|
||||
3. Use `build_library_async_logger(...)` instead when the library-facing async type should keep the broader `RuntimeSink` build path, including sync queue application through `build_logger(config.logger)`.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: build-library-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260520
|
||||
description: Build the library-facing sync logger facade from a LoggerConfig.
|
||||
update-time: 20260613
|
||||
description: Build the library-facing sync logger facade from a LoggerConfig by delegating to the configured runtime logger build path and then wrapping the result.
|
||||
key-word:
|
||||
- library
|
||||
- facade
|
||||
@@ -33,9 +33,15 @@ pub fn build_library_logger(config : LoggerConfig) -> LibraryLogger[RuntimeSink]
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This API builds a configured runtime logger first and then wraps it as `LibraryLogger`.
|
||||
- This API builds a configured runtime logger first and then wraps that same value as `LibraryLogger[RuntimeSink]`.
|
||||
- The embedded config still goes through the normal runtime logger build path, including runtime sink selection, optional queue wrapping, and timestamp application.
|
||||
- The returned facade wraps the same underlying `ConfiguredLogger` value that `build_logger(...)` would produce directly.
|
||||
- The facade intentionally exposes a smaller logging surface than the full configured runtime logger.
|
||||
- In particular, the configured runtime helper surface is preserved rather than rebuilt, but it is intentionally not directly exposed on the returned facade. Queue metrics, flush or drain helpers, and file controls stay behind `to_logger()` instead of disappearing.
|
||||
- The facade still preserves the underlying logger target rules on its exposed write methods: `log(..., target=...)` can override the target for one write, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless the facade first derived another logger with `with_target(...)` or `child(...)`.
|
||||
- Queue metrics, flush and drain helpers, and file runtime controls remain on the underlying `ConfiguredLogger`, not on the returned facade itself.
|
||||
- Call `to_logger()` if a caller must recover the underlying full logger object.
|
||||
- Use this builder when the boundary should preserve the configured runtime logger path but still hide broader runtime helper methods from downstream callers.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -52,15 +58,44 @@ let logger = build_library_logger(
|
||||
|
||||
In this example, the logger is built from config and then narrowed to the library facade.
|
||||
|
||||
#### When Need Runtime Helpers After Library-oriented Construction
|
||||
|
||||
When config-built runtime queue or file controls are still needed internally:
|
||||
```moonbit
|
||||
let logger = build_library_logger(config)
|
||||
let full = logger.to_logger()
|
||||
ignore(full.sink.pending_count())
|
||||
```
|
||||
|
||||
In this example, the library facade is unwrapped before using runtime-specific helpers through the preserved `RuntimeSink` value.
|
||||
|
||||
And the unwrapped value still carries the same `RuntimeSink` pipeline built from the original config.
|
||||
|
||||
And unlike `ApplicationLogger`, the narrower builder result does not expose those runtime helpers directly on the facade surface.
|
||||
|
||||
#### When Need A Per-call Target Override Through The Library Builder Facade
|
||||
|
||||
When typed library config should still build a facade that allows a one-write target override without unwrapping first:
|
||||
```moonbit
|
||||
let logger = build_library_logger(config)
|
||||
logger.log(Level::Error, "boom", target="lib.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `lib.audit` for that write.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the facade's stored target unless code derives another facade first with `with_target(...)` or `child(...)`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If backend-specific sink limitations exist, they still apply after the facade is built.
|
||||
|
||||
- If code later needs methods outside the library facade, it must unwrap with `to_logger()`.
|
||||
- If code later needs queue metrics, flush or drain helpers, or file runtime controls, it must unwrap with `to_logger()`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this facade when library APIs should not expose the full configured runtime logger type.
|
||||
|
||||
2. Use `parse_and_build_library_logger(...)` when starting from JSON text.
|
||||
|
||||
3. Use `to_logger()` when internal code later needs broader logger composition or direct access to the preserved `RuntimeSink` value without changing the public facade type.
|
||||
|
||||
@@ -33,9 +33,12 @@ pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `build_logger(...)` constructs the runtime sink shape based on `SinkConfig` and optional queue wrapper.
|
||||
- `build_logger(...)` first constructs a base `RuntimeSink` from `config.sink`, then applies `config.queue` when present, and finally builds `Logger::new(...)` with `config.min_level`, `config.target`, and `config.timestamp`.
|
||||
- The returned logger still supports normal logging methods because `ConfiguredLogger` is `Logger[RuntimeSink]`.
|
||||
- The returned logger also keeps inherited logger target behavior such as `with_target(...)`, `child(...)`, and per-call `target=` overrides on `log(...)`.
|
||||
- That means `log(..., target=...)` can override the target for one write, while severity helpers such as `info(...)`, `warn(...)`, and `error(...)` continue to use the stored logger target unless a derived logger was created first with `with_target(...)` or `child(...)`.
|
||||
- Queue metrics and file controls remain available through forwarding helpers on the configured logger.
|
||||
- `build_application_logger(...)` only re-exports this same configured runtime logger result under the `ApplicationLogger` alias, while `build_library_logger(...)` wraps the same result in `LibraryLogger[RuntimeSink]`.
|
||||
- This API is deterministic and data-driven, making it suitable for bootstrapping from parsed config.
|
||||
|
||||
### How to Use
|
||||
@@ -57,7 +60,19 @@ let logger = build_logger(
|
||||
|
||||
In this example, no JSON parsing is required because config objects were built directly.
|
||||
|
||||
And the runtime logger is ready immediately.
|
||||
And the runtime logger is ready immediately, with the same ordinary logger target semantics as any other `Logger` value.
|
||||
|
||||
#### When Need A Per-call Target Override After Typed Config Build
|
||||
|
||||
When typed config should still build a logger that supports a one-write target override:
|
||||
```moonbit
|
||||
let logger = build_logger(config)
|
||||
logger.log(Level::Error, "boom", target="svc.audit")
|
||||
```
|
||||
|
||||
In this example, the emitted record uses `svc.audit` for that write.
|
||||
|
||||
And later `info(...)`, `warn(...)`, or `error(...)` calls still use the logger's stored target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
|
||||
#### When Need Config-built Queue Or File Runtime Helpers
|
||||
|
||||
@@ -83,3 +98,5 @@ e.g.:
|
||||
|
||||
2. Use `parse_and_build_logger(...)` when the starting point is raw JSON text.
|
||||
|
||||
3. Use the application or library facade builders only when the boundary name or exposed surface should differ; they do not change the underlying configured runtime logger pipeline built here.
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: callback-sink-type
|
||||
group: api
|
||||
category: sink
|
||||
update-time: 20260613
|
||||
description: Public callback sink type used for forwarding structured records to user code.
|
||||
key-word:
|
||||
- sink
|
||||
- callback
|
||||
- type
|
||||
- public
|
||||
---
|
||||
|
||||
## Callback-sink-type
|
||||
|
||||
`CallbackSink` is the public callback sink type used for forwarding structured `Record` values to user code. It is the concrete sink type returned by `callback_sink(...)` and is intended for tests, adapters, and custom integrations that want raw record access.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub struct CallbackSink {
|
||||
callback : (Record) -> Unit
|
||||
}
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `CallbackSink` - Public synchronous sink type that forwards full `Record` values to a stored callback.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a public root struct, not a type alias.
|
||||
- The current field is `callback : (Record) -> Unit`.
|
||||
- `callback_sink(...)` constructs this type directly from a record callback.
|
||||
- Unlike `FormattedCallbackSink`, this sink preserves full structured record access instead of converting records into text first.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need A Typed Structured Callback Sink Value
|
||||
|
||||
When code should keep the concrete record-callback sink type visible:
|
||||
```moonbit
|
||||
let sink : CallbackSink = callback_sink(fn(rec) { println(rec.message) })
|
||||
```
|
||||
|
||||
In this example, the sink value stays explicit and preserves direct access to structured record data.
|
||||
|
||||
#### When Need A Typed Callback-backed Logger
|
||||
|
||||
When logging should preserve the raw-record callback sink type in the logger:
|
||||
```moonbit
|
||||
let logger : Logger[CallbackSink] = Logger::new(callback_sink(fn(rec) { println(rec.target) }))
|
||||
```
|
||||
|
||||
In this example, the concrete callback sink remains part of the logger type.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `CallbackSink` itself does not have a runtime failure mode.
|
||||
|
||||
- Behavior inside the stored callback is fully user-defined, so failures there are outside the sink type's own API contract.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `callback_sink(...)` when you need a value of this type.
|
||||
|
||||
2. Use `FormattedCallbackSink` when the destination expects final rendered text rather than full `Record` values.
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: color-mode
|
||||
group: api
|
||||
category: formatter
|
||||
update-time: 20260613
|
||||
description: Public color-mode enum alias used by text formatters and formatter config.
|
||||
key-word:
|
||||
- color
|
||||
- formatter
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Color-mode
|
||||
|
||||
`ColorMode` is the public enum that controls when ANSI color rendering is enabled for text formatting. It is a direct alias to the formatter enum used by both `text_formatter(...)` and `TextFormatterConfig::new(...)`.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type ColorMode = @utils.ColorMode
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `ColorMode` - Public formatter color-policy enum with the variants `Never`, `Auto`, and `Always`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a wrapper or a separate formatter mode.
|
||||
- `ColorMode::Never` disables ANSI color output.
|
||||
- `ColorMode::Always` always enables ANSI color rendering.
|
||||
- `ColorMode::Auto` currently follows the built-in `NO_COLOR` environment check.
|
||||
- The same enum is used by runtime formatters and serializable formatter config objects.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need Plain Text Without ANSI Codes
|
||||
|
||||
When logs should stay uncolored even if the terminal supports color:
|
||||
```moonbit
|
||||
let formatter = text_formatter(color_mode=ColorMode::Never)
|
||||
```
|
||||
|
||||
In this example, rendered text keeps the formatter output readable without ANSI escape sequences.
|
||||
|
||||
#### When Need Forced Terminal Colors
|
||||
|
||||
When tests or demos should always emit colored output:
|
||||
```moonbit
|
||||
let formatter = text_formatter(color_mode=ColorMode::Always)
|
||||
```
|
||||
|
||||
In this example, ANSI color rendering is enabled regardless of `NO_COLOR`.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `ColorMode` itself does not have a runtime failure mode.
|
||||
|
||||
- `ColorMode::Auto` is policy-based, so the final visible result still depends on environment state such as `NO_COLOR`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `color_mode_label(...)` when you need a stable string form for diagnostics or tests.
|
||||
|
||||
2. This enum controls whether color is used, while `ColorSupport` controls how rich the color encoding can be.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
name: color-support
|
||||
group: api
|
||||
category: formatter
|
||||
update-time: 20260613
|
||||
description: Public color-support enum alias used by text formatters and formatter config.
|
||||
key-word:
|
||||
- color
|
||||
- formatter
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Color-support
|
||||
|
||||
`ColorSupport` is the public enum that controls how much color precision a text formatter should use when ANSI color output is enabled. It is a direct alias to the formatter enum used by both runtime formatters and serializable formatter config.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type ColorSupport = @utils.ColorSupport
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `ColorSupport` - Public formatter color-capability enum with the variants `Basic` and `TrueColor`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a wrapper or a separate rendering engine.
|
||||
- `ColorSupport::Basic` prefers named/basic ANSI color codes.
|
||||
- `ColorSupport::TrueColor` allows 24-bit color codes when the style input uses values such as hex colors.
|
||||
- This setting only matters when color output is enabled through `ColorMode`.
|
||||
- The same enum is used by `text_formatter(...)` and `TextFormatterConfig::new(...)`.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need Conservative Basic ANSI Colors
|
||||
|
||||
When output should stay within the smaller named ANSI color set:
|
||||
```moonbit
|
||||
let formatter = text_formatter(
|
||||
color_mode=ColorMode::Always,
|
||||
color_support=ColorSupport::Basic,
|
||||
)
|
||||
```
|
||||
|
||||
In this example, style rendering prefers the basic color vocabulary instead of 24-bit codes.
|
||||
|
||||
#### When Need Hex-style Richer Color Rendering
|
||||
|
||||
When custom style tags should preserve truecolor output where possible:
|
||||
```moonbit
|
||||
let formatter = text_formatter(
|
||||
color_mode=ColorMode::Always,
|
||||
color_support=ColorSupport::TrueColor,
|
||||
)
|
||||
```
|
||||
|
||||
In this example, formatter styles can emit richer ANSI color codes for hex-based styles.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- `ColorSupport` itself does not have a runtime failure mode.
|
||||
|
||||
- If `ColorMode::Never` disables ANSI color output, changing `ColorSupport` does not produce a visible effect.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Use `color_support_label(...)` when you need a stable string form.
|
||||
|
||||
2. This enum controls color precision, not whether color rendering is enabled at all.
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
name: config-error
|
||||
group: api
|
||||
category: config
|
||||
update-time: 20260613
|
||||
description: Public config parsing error alias used by synchronous config-loading helpers.
|
||||
key-word:
|
||||
- config
|
||||
- error
|
||||
- alias
|
||||
- public
|
||||
---
|
||||
|
||||
## Config-error
|
||||
|
||||
`ConfigError` is the public error type raised by synchronous config parsing helpers. It is a direct alias to the internal config error definition and currently exposes a single structured error case for invalid input.
|
||||
|
||||
### Interface
|
||||
|
||||
```moonbit
|
||||
pub type ConfigError = @utils.ConfigError
|
||||
```
|
||||
|
||||
#### output
|
||||
|
||||
- `ConfigError` - Public config parsing error type with the case `InvalidConfig(String)`.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a separate public wrapper.
|
||||
- The current public error case is `ConfigError::InvalidConfig(message)`.
|
||||
- The alias is used by parsing helpers such as `parse_logger_config_text(...)` and by lower-level config parsing routines beneath it.
|
||||
- Error messages describe concrete schema problems such as invalid JSON, wrong value types, unsupported enum text, or missing required values for a chosen sink kind.
|
||||
|
||||
### How to Use
|
||||
|
||||
Here are some specific examples provided.
|
||||
|
||||
#### When Need To Catch Config Parse Failures
|
||||
|
||||
When raw config text should be validated before boot:
|
||||
```moonbit
|
||||
let config = parse_logger_config_text(raw) catch {
|
||||
err if err is ConfigError => {
|
||||
println(err.to_string())
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the caller keeps config validation failures separate from normal runtime work.
|
||||
|
||||
#### When Need To Surface A Clear Parse Message
|
||||
|
||||
When tooling should report why config input was rejected:
|
||||
```moonbit
|
||||
ignore(parse_logger_config_text("{bad json}")) catch {
|
||||
err => println(err.to_string())
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the error carries a concrete message instead of failing silently.
|
||||
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- Invalid JSON input raises `ConfigError::InvalidConfig(...)`.
|
||||
|
||||
- Wrong field types, unsupported level text, unsupported sink kinds, or an empty `path` for a file sink also raise `ConfigError::InvalidConfig(...)`.
|
||||
|
||||
### Notes
|
||||
|
||||
1. This alias currently belongs to the synchronous config-loading path in `bitlogger`.
|
||||
|
||||
2. Async config parsers in `bitlogger_async` currently raise the generic failure surface used by that package instead of `ConfigError`.
|
||||
@@ -2,8 +2,8 @@
|
||||
name: configured-logger-close
|
||||
group: api
|
||||
category: runtime
|
||||
update-time: 20260512
|
||||
description: Close the configured runtime logger sink and return whether the underlying sink reported a close action.
|
||||
update-time: 20260613
|
||||
description: Close the configured runtime logger sink and return whether the wrapped RuntimeSink reported a successful close action.
|
||||
key-word:
|
||||
- logger
|
||||
- runtime
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Configured-logger-close
|
||||
|
||||
Close the sink behind a `ConfiguredLogger`. This helper is the config-driven runtime close surface for queue-backed or file-backed sinks.
|
||||
Close the sink behind a `ConfiguredLogger`. This helper is the configured logger wrapper over `RuntimeSink::close(...)` for config-driven runtime teardown.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -27,16 +27,18 @@ pub fn ConfiguredLogger::close(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
#### output
|
||||
|
||||
- `Bool` - Whether the underlying runtime sink reported a successful close action.
|
||||
- `Bool` - Whether the wrapped `RuntimeSink::close(...)` call reported a successful close action.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Queue-backed file sinks close the wrapped file sink.
|
||||
- Plain file sinks forward directly to file close behavior.
|
||||
- Console-style sinks usually report `true` because they do not have a meaningful close step.
|
||||
- This helper delegates to `RuntimeSink::close(...)` through the configured logger wrapper.
|
||||
- This helper delegates directly to `self.sink.close()`.
|
||||
- Plain file sinks forward to `FileSink::close()` through `RuntimeSink`.
|
||||
- Queue-backed file sinks close the wrapped file sink instead of only the queue wrapper.
|
||||
- Generic `close()` on queued file sinks does not drain pending queue entries first; it closes the wrapped file sink directly.
|
||||
- Console-style sinks and queue-wrapped console-style sinks return `true` as a no-op success because they do not expose a meaningful close step here.
|
||||
- For file-backed configured loggers, later `close()` calls return `false` after the wrapped file handle has already been cleared.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -63,7 +65,9 @@ In this example, callers can branch on the reported close result.
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the runtime sink has no real close action, the helper may still return `true` as a no-op success.
|
||||
- If the configured runtime sink shape has no real close action, the helper may still return `true` as a no-op success.
|
||||
|
||||
- If the configured logger shares the same wrapped runtime sink state with another facade and one path already closed that file-backed sink, a later close attempt returns `false`.
|
||||
|
||||
- If callers need a file-specific close path with queue flush nuances, `file_close()` may be the better API.
|
||||
|
||||
@@ -71,4 +75,6 @@ e.g.:
|
||||
|
||||
1. This is the generic configured runtime close helper.
|
||||
|
||||
2. Prefer file-specific helpers when the sink shape is known to be file-backed.
|
||||
2. Prefer `file_close()` when the configured sink shape is file-backed and queued records should be flushed before teardown.
|
||||
|
||||
3. Converting the same configured logger through wrapper paths such as library projection still shares the wrapped runtime sink state, so close effects are visible across those facades.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: configured-logger-drain
|
||||
group: api
|
||||
category: runtime
|
||||
update-time: 20260512
|
||||
description: Drain queued work from a configured runtime logger with optional item limits.
|
||||
update-time: 20260613
|
||||
description: Drain queued work from a configured runtime logger with optional item limits through RuntimeSink.
|
||||
key-word:
|
||||
- logger
|
||||
- runtime
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Configured-logger-drain
|
||||
|
||||
Drain queued work from a `ConfiguredLogger`. This helper is useful when config-driven queue wrapping should be advanced in a controlled, bounded way.
|
||||
Drain queued work from a `ConfiguredLogger`. This helper is the configured logger wrapper over `RuntimeSink::drain(...)` when config-driven queue wrapping should be advanced in a controlled, bounded way.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -28,16 +28,16 @@ pub fn ConfiguredLogger::drain(self : ConfiguredLogger, max_items~ : Int = -1) -
|
||||
|
||||
#### output
|
||||
|
||||
- `Int` - Number of drained items.
|
||||
- `Int` - Count returned by the wrapped `RuntimeSink::drain(...)` call.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Queue-wrapped sinks may drain up to `max_items` records.
|
||||
- For plain file sinks, the runtime falls back to file flush behavior instead of queue draining.
|
||||
- For sinks without queue semantics, the result is typically `0`.
|
||||
- This helper delegates to `RuntimeSink::drain(...)` through the configured logger wrapper.
|
||||
- This helper delegates directly to `self.sink.drain(max_items=max_items)`.
|
||||
- Queue-wrapped sinks forward to the concrete queue sink's `drain(...)` behavior and may drain up to `max_items` records.
|
||||
- Plain file sinks fall back to `FileSink::flush()` behavior through `RuntimeSink` and return `1` or `0`.
|
||||
- Plain console-style sinks return `0` because they do not own a drainable queue here.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -64,7 +64,7 @@ In this example, the configured runtime logger drains without imposing an item c
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the runtime sink is not queue-backed, draining may return `0` or follow fallback flush behavior.
|
||||
- If the configured runtime sink is not queue-backed, draining may return `0` or follow the plain-file flush fallback.
|
||||
|
||||
- If callers only need generic flush semantics, `flush()` may be the simpler API.
|
||||
|
||||
@@ -72,4 +72,4 @@ e.g.:
|
||||
|
||||
1. Prefer this helper when queue progress should be bounded or observable.
|
||||
|
||||
2. Use `pending_count()` to inspect remaining backlog after the drain call.
|
||||
2. Use `pending_count()` to inspect remaining backlog after the drain call when the configured sink is queue-backed.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: configured-logger-dropped-count
|
||||
group: api
|
||||
category: runtime
|
||||
update-time: 20260512
|
||||
description: Read the cumulative dropped-record count from a configured runtime logger.
|
||||
update-time: 20260613
|
||||
description: Read the cumulative dropped-record count from a configured runtime logger through RuntimeSink.
|
||||
key-word:
|
||||
- logger
|
||||
- runtime
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Configured-logger-dropped-count
|
||||
|
||||
Read the cumulative dropped-record count from a `ConfiguredLogger`. This helper is useful when config-driven queue wrapping may discard records under pressure.
|
||||
Read the cumulative dropped-record count from a `ConfiguredLogger`. This helper is the configured logger wrapper over `RuntimeSink::dropped_count(...)` when config-driven queue wrapping may discard records under pressure.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -27,16 +27,16 @@ pub fn ConfiguredLogger::dropped_count(self : ConfiguredLogger) -> Int {}
|
||||
|
||||
#### output
|
||||
|
||||
- `Int` - Number of dropped records reported by the runtime sink.
|
||||
- `Int` - Number returned by the wrapped `RuntimeSink::dropped_count()` call.
|
||||
|
||||
### Explanation
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Queue-backed sinks return their live dropped-count metric.
|
||||
- Non-queued sinks report `0`.
|
||||
- The counter is cumulative for the runtime sink lifetime.
|
||||
- This helper delegates to `RuntimeSink::dropped_count(...)` through the configured logger wrapper.
|
||||
- This helper delegates directly to `self.sink.dropped_count()`.
|
||||
- Queue-backed runtime sink variants return their live dropped-count metric.
|
||||
- Plain console and plain file runtime sink variants return `0` because they do not track queued record drops.
|
||||
- The counter is cumulative for the lifetime of the concrete runtime sink value owned by the configured logger.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -65,7 +65,7 @@ In this example, the helper exposes the metric needed to compare runtime queue t
|
||||
### Error Case
|
||||
|
||||
e.g.:
|
||||
- If the logger is not queue-backed, the method simply returns `0`.
|
||||
- If the configured logger is not queue-backed, the method simply returns `0`.
|
||||
|
||||
- If callers need queue shape and file status together, `file_runtime_state()` may carry more useful context for file sinks.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_append_mode(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks report their current append policy.
|
||||
- Queued file sinks forward the policy from the wrapped file sink.
|
||||
- File-backed sinks report their current append policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the policy from the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper reports runtime file policy, not whether a file is currently writable.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_auto_flush(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks report their current auto-flush policy.
|
||||
- Queued file sinks forward the policy from the wrapped file sink.
|
||||
- File-backed sinks report their current auto-flush policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the policy from the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper exposes policy state only and does not force any flush action.
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ pub fn ConfiguredLogger::file_available(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed runtime sinks report actual file availability.
|
||||
- File-backed runtime sinks report actual file availability through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks still expose the availability of their wrapped inner file sink.
|
||||
- Non-file sinks report `false`.
|
||||
- Queued file sinks still expose the availability of their wrapped file sink.
|
||||
- This helper delegates to the runtime sink and does not mutate logger state.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_clear_rotation(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks clear their runtime rotation policy.
|
||||
- Queued file sinks forward the update to the wrapped file sink.
|
||||
- File-backed sinks clear their runtime rotation policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the update to the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper is equivalent in intent to setting rotation to `None`, but is clearer at the call site.
|
||||
|
||||
|
||||
@@ -33,10 +33,11 @@ pub fn ConfiguredLogger::file_close(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Plain file sinks forward directly to file close behavior.
|
||||
- Queued file sinks flush queue work before closing the wrapped file sink.
|
||||
- Plain file sinks forward directly to file close behavior through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks flush queue work before closing the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper is narrower than generic `close()` because it specifically targets file sink shutdown.
|
||||
- After a file-backed configured logger has already cleared its file handle, later `file_close()` calls return `false`.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -65,10 +66,14 @@ In this example, the result describes file close behavior rather than generic si
|
||||
e.g.:
|
||||
- If the configured sink is not file-backed, the method returns `false`.
|
||||
|
||||
- If the file handle was already closed earlier through this logger or another facade sharing the same wrapped runtime sink state, the method returns `false`.
|
||||
|
||||
- If callers only need generic sink teardown, `close()` is the broader API.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this helper when file-backed runtime behavior matters specifically.
|
||||
|
||||
2. Queued file sinks may flush pending records before closing the file.
|
||||
2. Queued file sinks flush pending records before closing the file, unlike generic `close()`.
|
||||
|
||||
3. Library or application facades derived from the same configured runtime logger still observe the same underlying file-close state.
|
||||
|
||||
@@ -33,9 +33,9 @@ pub fn ConfiguredLogger::file_default_policy(self : ConfiguredLogger) -> FileSin
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks return the default policy captured at creation time.
|
||||
- Queued file sinks forward the default policy from the wrapped file sink.
|
||||
- Non-file sinks return a neutral fallback policy value.
|
||||
- File-backed sinks return the default policy captured at creation time through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the default policy from the wrapped inner file sink.
|
||||
- Non-file sinks return the same neutral fallback policy value produced by `RuntimeSink::file_default_policy()`.
|
||||
- This helper is useful when callers need to compare runtime drift or restore defaults later.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_flush_failures(self : ConfiguredLogger) -> Int {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks report their recorded flush-failure count.
|
||||
- Queued file sinks forward the metric from the wrapped file sink.
|
||||
- File-backed sinks report their recorded flush-failure count through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the metric from the wrapped inner file sink.
|
||||
- Non-file sinks return `0`.
|
||||
- The counter is cumulative until reset.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: configured-logger-file-flush
|
||||
group: api
|
||||
category: runtime
|
||||
update-time: 20260512
|
||||
update-time: 20260614
|
||||
description: Flush the file sink behind a configured runtime logger when one is present.
|
||||
key-word:
|
||||
- logger
|
||||
@@ -33,10 +33,13 @@ pub fn ConfiguredLogger::file_flush(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Plain file sinks forward directly to file flush behavior.
|
||||
- Queued file sinks first flush queued records, then flush the wrapped file sink.
|
||||
- Plain file sinks forward directly to file flush behavior through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks first flush queued records, then flush the wrapped inner file sink.
|
||||
- For queued file sinks, the returned `Bool` comes from the inner file flush rather than the queue flush step.
|
||||
- For queued file sinks, this step may also be the point where queued records finally hit the inner file sink, so write-failure counters can change here even if earlier log calls only queued records.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper is narrower than generic `flush()` because it targets file sink behavior specifically.
|
||||
- After a file-backed configured logger has already cleared its file handle, later `file_flush()` calls return `false`.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -65,10 +68,14 @@ In this example, callers can distinguish file flush success from a non-file sink
|
||||
e.g.:
|
||||
- If the configured sink is not file-backed, the method returns `false`.
|
||||
|
||||
- If the file handle was already closed earlier through this logger or another facade sharing the same wrapped runtime sink state, the method returns `false`.
|
||||
|
||||
- If callers want generic queue or sink advancement instead of file-specific behavior, `flush()` is the broader API.
|
||||
|
||||
### Notes
|
||||
|
||||
1. Prefer this helper when the configured sink is known to be file-backed.
|
||||
|
||||
2. Queued file sinks may perform both queue flush and file flush work here.
|
||||
2. Queued file sinks may perform both queue flush and file flush work here, including surfacing delayed write failures from previously queued records.
|
||||
|
||||
3. Library or application facades derived from the same configured runtime logger still observe the same underlying file-flush availability state.
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_open_failures(self : ConfiguredLogger) -> Int {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks report their recorded open-failure count.
|
||||
- Queued file sinks forward the metric from the wrapped file sink.
|
||||
- File-backed sinks report their recorded open-failure count through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the metric from the wrapped inner file sink.
|
||||
- Non-file sinks return `0`.
|
||||
- The counter is cumulative until reset.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_path(self : ConfiguredLogger) -> String {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks return their current file path.
|
||||
- Queued file sinks forward the wrapped file sink path.
|
||||
- File-backed sinks return their current file path through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the wrapped inner file sink path.
|
||||
- Non-file sinks return an empty string.
|
||||
- This helper is observation-only and does not modify file state.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_policy_matches_default(self : ConfiguredLogger) ->
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks compare current runtime file policy against their stored defaults.
|
||||
- Queued file sinks forward the comparison from the wrapped file sink.
|
||||
- File-backed sinks compare current runtime file policy against their stored defaults through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the comparison from the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper is a compact drift signal when callers do not need to compare full policy objects directly.
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ pub fn ConfiguredLogger::file_policy(self : ConfiguredLogger) -> FileSinkPolicy
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks return their current runtime file policy.
|
||||
- Queued file sinks forward the policy from the wrapped file sink.
|
||||
- Non-file sinks return a neutral fallback policy value.
|
||||
- File-backed sinks return their current runtime file policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the policy from the wrapped inner file sink.
|
||||
- Non-file sinks return the same neutral fallback policy value produced by `RuntimeSink::file_policy()`.
|
||||
- This helper is broader than `file_append_mode()` or `file_auto_flush()` because it returns the whole policy object.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_reopen_append(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Plain file sinks reopen in append mode.
|
||||
- Queued file sinks forward reopen behavior to the wrapped file sink.
|
||||
- Plain file sinks reopen in append mode through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward reopen behavior to the wrapped inner file sink.
|
||||
- This helper is a specialized shortcut for a common reopen mode.
|
||||
- Non-file sinks return `false`.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_reopen_truncate(self : ConfiguredLogger) -> Bool {
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Plain file sinks reopen in truncate mode.
|
||||
- Queued file sinks forward reopen behavior to the wrapped file sink.
|
||||
- Plain file sinks reopen in truncate mode through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward reopen behavior to the wrapped inner file sink.
|
||||
- This helper is a specialized shortcut for a common reset-style reopen mode.
|
||||
- Non-file sinks return `false`.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_reopen_with_current_policy(self : ConfiguredLogger
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Plain file sinks reuse their current stored reopen policy.
|
||||
- Queued file sinks forward reopen behavior to the wrapped file sink.
|
||||
- Plain file sinks reuse their current stored reopen policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward reopen behavior to the wrapped inner file sink.
|
||||
- This helper differs from `file_reopen(...)` because it does not accept a per-call append override.
|
||||
- Non-file sinks return `false`.
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ pub fn ConfiguredLogger::file_reopen(self : ConfiguredLogger, append~ : Bool? =
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- Plain file sinks reopen directly.
|
||||
- Queued file sinks forward reopen behavior to the wrapped file sink.
|
||||
- Plain file sinks reopen directly through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward reopen behavior to the wrapped inner file sink.
|
||||
- `append=None` preserves current reopen policy, while `Some(true/false)` overrides append mode.
|
||||
- Non-file sinks return `false`.
|
||||
|
||||
|
||||
@@ -72,4 +72,4 @@ e.g.:
|
||||
|
||||
1. Use this helper after diagnostics or recovery, not before capturing needed evidence.
|
||||
|
||||
2. It is the reset companion for the file failure-counter helpers.
|
||||
2. For queued file sinks, it resets the inner file counters only; it does not clear still-pending queued records that may produce new failures on a later `file_flush()`.
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_reset_policy(self : ConfiguredLogger) -> Bool {}
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks restore their stored default file policy.
|
||||
- Queued file sinks forward the reset behavior to the wrapped file sink.
|
||||
- File-backed sinks restore their stored default file policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the reset behavior to the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper is the inverse of runtime policy drift, not a generic reopen or flush action.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_rotation_config(self : ConfiguredLogger) -> FileRo
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks return their current rotation configuration when enabled.
|
||||
- Queued file sinks forward the config from the wrapped file sink.
|
||||
- File-backed sinks return their current rotation configuration when enabled through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the config from the wrapped inner file sink.
|
||||
- Non-file sinks return `None`.
|
||||
- This helper is useful when callers need active runtime rotation parameters rather than only a boolean flag.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_rotation_enabled(self : ConfiguredLogger) -> Bool
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks report whether a rotation config is active.
|
||||
- Queued file sinks forward the state from the wrapped file sink.
|
||||
- File-backed sinks report whether a rotation config is active through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the state from the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper is narrower than `file_rotation_config()` when only a yes/no check is needed.
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ pub fn ConfiguredLogger::file_rotation_failures(self : ConfiguredLogger) -> Int
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks report their recorded rotation-failure count.
|
||||
- Queued file sinks forward the metric from the wrapped file sink.
|
||||
- File-backed sinks report their recorded rotation-failure count through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the metric from the wrapped inner file sink.
|
||||
- Non-file sinks return `0`.
|
||||
- The counter is cumulative until reset.
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn ConfiguredLogger::file_runtime_state(self : ConfiguredLogger) -> RuntimeF
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks return `Some(RuntimeFileState)`.
|
||||
- File-backed sinks return `Some(RuntimeFileState)` through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks include both file status and queue metrics in the returned state.
|
||||
- Non-file sinks return `None`.
|
||||
- This helper is richer than `file_state()` because it can also surface queued backlog and dropped counts.
|
||||
|
||||
@@ -34,8 +34,8 @@ pub fn ConfiguredLogger::file_set_append_mode(self : ConfiguredLogger, append :
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks update their stored append policy.
|
||||
- Queued file sinks forward the policy update to the wrapped file sink.
|
||||
- File-backed sinks update their stored append policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the policy update to the wrapped inner file sink.
|
||||
- This helper updates policy only; it does not force immediate reopen.
|
||||
- Non-file sinks return `false`.
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ pub fn ConfiguredLogger::file_set_auto_flush(self : ConfiguredLogger, enabled :
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- File-backed sinks update their runtime auto-flush policy.
|
||||
- Queued file sinks forward the update to the wrapped file sink.
|
||||
- File-backed sinks update their runtime auto-flush policy through the wrapped `RuntimeSink`.
|
||||
- Queued file sinks forward the update to the wrapped inner file sink.
|
||||
- Non-file sinks return `false`.
|
||||
- This helper changes policy only; it does not itself flush pending data.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user