feat: more granular controls for logging

pull/399/head
Kobi Meirson 2022-10-19 22:46:38 +03:00
parent 1476d2965d
commit 6ed11f176c
No known key found for this signature in database
GPG Key ID: 5D66F732B037CDE1
25 changed files with 176 additions and 20 deletions

View File

@ -110,7 +110,7 @@ export default (domains, global) => {
if (global.logging.accessLog.computed) { if (global.logging.accessLog.computed) {
config.http.push(['access_log', global.logging.accessLogPath.computed.trim() + config.http.push(['access_log', global.logging.accessLogPath.computed.trim() +
(global.logging.cloudflare.computed ? ' cloudflare' : '') + (global.logging.cloudflare.computed ? ' cloudflare' : '') +
(global.logging.accessLogArguments.computed ? ` ${global.logging.accessLogArguments.computed.trim()}` : ''), (global.logging.accessLogParameters.computed ? ` ${global.logging.accessLogParameters.computed.trim()}` : ''),
]); ]);
} else { } else {
config.http.push(['access_log', 'off']); config.http.push(['access_log', 'off']);

View File

@ -25,7 +25,6 @@ THE SOFTWARE.
*/ */
import { getSslCertificate, getSslCertificateKey } from '../../util/get_ssl_certificate'; import { getSslCertificate, getSslCertificateKey } from '../../util/get_ssl_certificate';
import { getAccessLogDomainPath, getErrorLogDomainPath } from '../../util/get_log_paths';
import { extensions, gzipTypes } from '../../util/types_extensions'; import { extensions, gzipTypes } from '../../util/types_extensions';
import commonHsts from '../../util/common_hsts'; import commonHsts from '../../util/common_hsts';
import securityConf from './security.conf'; import securityConf from './security.conf';
@ -226,13 +225,16 @@ export default (domain, domains, global, ipPortPairs) => {
if (domain.logging.accessLog.computed) if (domain.logging.accessLog.computed)
serverConfig.push(['access_log', serverConfig.push(['access_log',
getAccessLogDomainPath(domain, global) + domain.logging.accessLogPath.computed.trim() +
(global.logging.cloudflare.computed ? ' cloudflare' : '') + (global.logging.cloudflare.computed ? ' cloudflare' : '') +
(global.logging.accessLogArguments.computed ? ` ${global.logging.accessLogArguments.computed.trim()}`: ''), (domain.logging.accessLogParameters.computed ? ` ${domain.logging.accessLogParameters.computed.trim()}`: ''),
]); ]);
if (domain.logging.errorLog.computed) if (domain.logging.errorLog.computed)
serverConfig.push(['error_log', getErrorLogDomainPath(domain, global)]); serverConfig.push(['error_log',
domain.logging.errorLogPath.computed.trim() +
` ${domain.logging.errorLogLevel.computed}`,
]);
} }
// index.php // index.php

View File

@ -27,4 +27,6 @@ THE SOFTWARE.
export default { export default {
byDomain: 'der Domain', byDomain: 'der Domain',
enableForThisDomain: 'Für diese Domain aktivieren', enableForThisDomain: 'Für diese Domain aktivieren',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} "Seite nicht gefunden" Error Logging in`, enableFileNotFoundErrorLogging: `${common.enable} "Seite nicht gefunden" Error Logging in`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'Füge Cloudflare Anfrage-Header dem Standard Log-Format hinzu', enableCloudflare: 'Füge Cloudflare Anfrage-Header dem Standard Log-Format hinzu',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: 'by domain', byDomain: 'by domain',
enableForThisDomain: `${common.enable} for this domain`, enableForThisDomain: `${common.enable} for this domain`,
arguments: 'arguments',
level: 'logging level',
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} file not found error logging in`, enableFileNotFoundErrorLogging: `${common.enable} file not found error logging in`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments',
level: 'logging level',
enableCloudflare: 'add Cloudflare request headers to the default log format', enableCloudflare: 'add Cloudflare request headers to the default log format',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: 'por dominio', byDomain: 'por dominio',
enableForThisDomain: `${common.enable} para este dominio`, enableForThisDomain: `${common.enable} para este dominio`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} el registro de error de archivo no encontrado`, enableFileNotFoundErrorLogging: `${common.enable} el registro de error de archivo no encontrado`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'agregar cabecera de petición de Cloudflare en el formato por defecto del registro', enableCloudflare: 'agregar cabecera de petición de Cloudflare en el formato por defecto del registro',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: 'par domaine', byDomain: 'par domaine',
enableForThisDomain: `${common.enable} pour ce domaine`, enableForThisDomain: `${common.enable} pour ce domaine`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} les erreurs de fichiers introuvables lors de la journalisation`, enableFileNotFoundErrorLogging: `${common.enable} les erreurs de fichiers introuvables lors de la journalisation`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'ajouter les en-têtes de requête CloudFlare au format de journal par défaut', enableCloudflare: 'ajouter les en-têtes de requête CloudFlare au format de journal par défaut',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: '(ドメインごと)', byDomain: '(ドメインごと)',
enableForThisDomain: `このドメインで${common.enable}`, enableForThisDomain: `このドメインで${common.enable}`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `FILE NOT FOUND エラーのロギングを${common.enable}`, enableFileNotFoundErrorLogging: `FILE NOT FOUND エラーのロギングを${common.enable}`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'デフォルトのログフォーマットに Cloudflare のリクエストヘッダを追加する', enableCloudflare: 'デフォルトのログフォーマットに Cloudflare のリクエストヘッダを追加する',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: 'wg. domen', byDomain: 'wg. domen',
enableForThisDomain: `${common.enable} dla tej domeny`, enableForThisDomain: `${common.enable} dla tej domeny`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} logowanie błędów o nieznalezionych plikach`, enableFileNotFoundErrorLogging: `${common.enable} logowanie błędów o nieznalezionych plikach`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'dodaj nagłówki żądań Cloudflare do domyślnego formatu dziennika ', enableCloudflare: 'dodaj nagłówki żądań Cloudflare do domyślnego formatu dziennika ',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: 'por domínio', byDomain: 'por domínio',
enableForThisDomain: `${common.enable} para este domínio`, enableForThisDomain: `${common.enable} para este domínio`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} erro de arquivo não encontrado ao fazer login`, enableFileNotFoundErrorLogging: `${common.enable} erro de arquivo não encontrado ao fazer login`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'adicionar cabeçalhos de solicitação Cloudflare ao formato de log padrão', enableCloudflare: 'adicionar cabeçalhos de solicitação Cloudflare ao formato de log padrão',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: 'по домену', byDomain: 'по домену',
enableForThisDomain: `${common.enable} для этого домена`, enableForThisDomain: `${common.enable} для этого домена`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable} логирование ошибок для файлов, которые не были найдены при запросе`, enableFileNotFoundErrorLogging: `${common.enable} логирование ошибок для файлов, которые не были найдены при запросе`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: 'добавить Cloudflare хедеры запроса в дефолтный формат логов', enableCloudflare: 'добавить Cloudflare хедеры запроса в дефолтный формат логов',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: '在此站点', byDomain: '在此站点',
enableForThisDomain: `为此站点${common.enable}`, enableForThisDomain: `为此站点${common.enable}`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable}“文件未找到”错误日志:`, enableFileNotFoundErrorLogging: `${common.enable}“文件未找到”错误日志:`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: '将Cloudflare请求头部添加到默认日志格式', enableCloudflare: '将Cloudflare请求头部添加到默认日志格式',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -29,4 +29,6 @@ import common from '../../common';
export default { export default {
byDomain: '在此網域', byDomain: '在此網域',
enableForThisDomain: `為此網域${common.enable}`, enableForThisDomain: `為此網域${common.enable}`,
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
}; };

View File

@ -29,6 +29,8 @@ import common from '../../common';
export default { export default {
enableFileNotFoundErrorLogging: `${common.enable}「找不到檔案」錯誤日誌:`, enableFileNotFoundErrorLogging: `${common.enable}「找不到檔案」錯誤日誌:`,
logformat: 'log_format', logformat: 'log_format',
arguments: 'arguments', // TODO: translate
level: 'logging level', // TODO: translate
enableCloudflare: '將 Cloudflare 請求標頭加入預設日誌格式', enableCloudflare: '將 Cloudflare 請求標頭加入預設日誌格式',
cfRay: 'CF-Ray', cfRay: 'CF-Ray',
cfConnectingIp: 'CF-Connecting-IP', cfConnectingIp: 'CF-Connecting-IP',

View File

@ -39,6 +39,32 @@ THE SOFTWARE.
</PrettyCheck> </PrettyCheck>
</div> </div>
</div> </div>
<div v-if="$props.data.accessLog.computed" class="control field is-horizontal is-expanded">
<input
v-model="accessLogPath"
class="input"
type="text"
:placeholder="$props.data.accessLogPath.computed"
/>
</div>
</div>
</div>
</div>
<div v-if="$props.data.accessLog.computed" class="field is-horizontal">
<div class="field-label">
<label class="label">access_log {{ $t('templates.domainSections.logging.arguments') }}</label>
</div>
<div class="field-body">
<div class="field">
<div :class="`control${accessLogParametersChanged ? ' is-changed' : ''}`">
<input
v-model="accessLogParameters"
class="input"
type="text"
:placeholder="$props.data.accessLogParameters.default"
/>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -55,6 +81,34 @@ THE SOFTWARE.
{{ $t('templates.domainSections.logging.enableForThisDomain') }} {{ $t('templates.domainSections.logging.enableForThisDomain') }}
</PrettyCheck> </PrettyCheck>
</div> </div>
<div v-if="$props.data.errorLog.computed" class="control field is-horizontal is-expanded">
<input
v-model="errorLogPath"
class="input"
type="text"
:placeholder="$props.data.errorLogPath.computed"
/>
</div>
</div>
</div>
</div>
</div>
<div v-if="$props.data.errorLog.computed" class="field is-horizontal">
<div class="field-label">
<label class="label">error_log {{ $t('templates.domainSections.logging.level') }}</label>
</div>
<div class="field-body">
<div class="field is-horizontal">
<div
v-for="value in $props.data.errorLogLevel.options"
:class="`control${errorLogLevelChanged && value === errorLogLevel ? ' is-changed' : ''}`"
>
<div class="radio">
<PrettyRadio v-model="errorLogLevel" :value="value" class="p-default p-round p-fill p-icon">
{{ value }}
</PrettyRadio>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -65,17 +119,38 @@ THE SOFTWARE.
<script> <script>
import delegatedFromDefaults from '../../util/delegated_from_defaults'; import delegatedFromDefaults from '../../util/delegated_from_defaults';
import computedFromDefaults from '../../util/computed_from_defaults'; import computedFromDefaults from '../../util/computed_from_defaults';
import { accessLogParamsDefault, errorLogLevelDefault, errorLogLevelOptions } from '../../util/logging';
import PrettyCheck from '../inputs/checkbox'; import PrettyCheck from '../inputs/checkbox';
import PrettyRadio from '../inputs/radio';
const defaults = { const defaults = {
accessLog: { accessLog: {
default: true, default: true,
enabled: true, enabled: true,
}, },
accessLogPath: {
default: '',
computed: '/var/log/nginx/example.com.access.log', // No default value, but a default computed
enabled: true,
},
accessLogParameters: {
default: accessLogParamsDefault,
enabled: true,
},
errorLog: { errorLog: {
default: true, default: true,
enabled: true, enabled: true,
}, },
errorLogPath: {
default: '',
computed: '/var/log/nginx/example.com.error.log', // No default value, but a default computed
enabled: true,
},
errorLogLevel: {
default: errorLogLevelDefault,
options: errorLogLevelOptions,
enabled: true,
},
}; };
export default { export default {
@ -85,10 +160,24 @@ THE SOFTWARE.
delegated: delegatedFromDefaults(defaults), // Data the parent will present here delegated: delegatedFromDefaults(defaults), // Data the parent will present here
components: { components: {
PrettyCheck, PrettyCheck,
PrettyRadio,
}, },
props: { props: {
data: Object, // Data delegated back to us from parent data: Object, // Data delegated back to us from parent
}, },
computed: computedFromDefaults(defaults, 'logging'), // Getters & setters for the delegated data computed: computedFromDefaults(defaults, 'logging'), // Getters & setters for the delegated data
watch: {
'$parent.$props.data.server.domain': {
handler(data) {
if (!this.$props.data.accessLogPath.value.trim()) {
this.$props.data.accessLogPath.computed = `/var/log/nginx/${data.computed}.access.log`;
}
if (!this.$props.data.errorLogPath.value.trim()) {
this.$props.data.errorLogPath.computed = `/var/log/nginx/${data.computed}.error.log`;
}
},
deep: true,
},
},
}; };
</script> </script>

View File

@ -51,18 +51,18 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div class="field is-horizontal"> <div v-if="$props.data.accessLog.computed" class="field is-horizontal">
<div class="field-label"> <div class="field-label">
<label class="label">access_log arguments</label> <label class="label">access_log {{ $t('templates.globalSections.logging.arguments') }}</label>
</div> </div>
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${accessLogArgumentsChanged ? ' is-changed' : ''}`"> <div :class="`control${accessLogParametersChanged ? ' is-changed' : ''}`">
<input <input
v-model="accessLogArguments" v-model="accessLogParameters"
class="input" class="input"
type="text" type="text"
:placeholder="$props.data.accessLogArguments.default" :placeholder="$props.data.accessLogParameters.default"
/> />
</div> </div>
</div> </div>
@ -94,6 +94,26 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div v-if="$props.data.errorLog.computed" class="field is-horizontal">
<div class="field-label">
<label class="label">error_log {{ $t('templates.globalSections.logging.level') }}</label>
</div>
<div class="field-body">
<div class="field is-horizontal">
<div
v-for="value in $props.data.errorLogLevel.options"
:class="`control${errorLogLevelChanged && value === errorLogLevel ? ' is-changed' : ''}`"
>
<div class="radio">
<PrettyRadio v-model="errorLogLevel" :value="value" class="p-default p-round p-fill p-icon">
{{ value }}
</PrettyRadio>
</div>
</div>
</div>
</div>
</div>
<div class="field is-horizontal is-aligned-top"> <div class="field is-horizontal is-aligned-top">
<div class="field-label"> <div class="field-label">
<label class="label">log_not_found</label> <label class="label">log_not_found</label>
@ -189,7 +209,9 @@ THE SOFTWARE.
<script> <script>
import delegatedFromDefaults from '../../util/delegated_from_defaults'; import delegatedFromDefaults from '../../util/delegated_from_defaults';
import computedFromDefaults from '../../util/computed_from_defaults'; import computedFromDefaults from '../../util/computed_from_defaults';
import { accessLogParamsDefault, errorLogLevelDefault, errorLogLevelOptions } from '../../util/logging';
import PrettyCheck from '../inputs/checkbox'; import PrettyCheck from '../inputs/checkbox';
import PrettyRadio from '../inputs/radio';
const defaults = { const defaults = {
accessLog: { accessLog: {
@ -200,8 +222,8 @@ THE SOFTWARE.
default: '/var/log/nginx/access.log', default: '/var/log/nginx/access.log',
enabled: true, enabled: true,
}, },
accessLogArguments: { accessLogParameters: {
default: 'buffer=512k flush=1m', default: accessLogParamsDefault,
enabled: true, enabled: true,
}, },
errorLog: { errorLog: {
@ -209,7 +231,12 @@ THE SOFTWARE.
enabled: true, enabled: true,
}, },
errorLogPath: { errorLogPath: {
default: '/var/log/nginx/error.log warn', default: '/var/log/nginx/error.log',
enabled: true,
},
errorLogLevel: {
default: errorLogLevelDefault,
options: errorLogLevelOptions,
enabled: true, enabled: true,
}, },
logNotFound: { logNotFound: {
@ -261,6 +288,7 @@ THE SOFTWARE.
delegated: delegatedFromDefaults(defaults), // Data the parent will present here delegated: delegatedFromDefaults(defaults), // Data the parent will present here
components: { components: {
PrettyCheck, PrettyCheck,
PrettyRadio,
}, },
props: { props: {
data: Object, // Data delegated back to us from parent data: Object, // Data delegated back to us from parent

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,10 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
export const getAccessLogDomainPath = (domain, global) => { export const accessLogParamsDefault = 'buffer=512k flush=1m';
return global.logging.accessLogPath.computed.replace(/([^/]+)\.log$/, `${domain.server.domain.computed}.$1.log`);
};
export const getErrorLogDomainPath = (domain, global) => { export const errorLogLevelDefault = 'warn';
return global.logging.errorLogPath.computed.replace(/([^/]+)\.log (.+)$/, `${domain.server.domain.computed}.$1.log $2`); export const errorLogLevelOptions = Object.freeze(['debug', 'info', 'notice', 'warn', 'error', 'crit', 'alert', 'emerg']);
};