@ data-fair/ lib- 节点
由数据公平堆栈(数据公平、处理、事件、目录等)服务共享的服务器侧节点功能: HTTP客户端针对SSF,Prometheus可观察性,MongoDB帮助器,升级脚本,websocket发报器和客户端进行保护.
安装
npm i @data-fair/lib-node
端口依赖, 所有声明的可选性 : 安装您导入的模块所需的模块 .
| 同伴依赖关系 | 需要满足 |
|---|---|
prom-client@15 | observer.js, (中文(简体) ), http-agents.js 以及他们赖以生存的一切axios.js, (中文(简体) ), events-queue.js没有它 log.js 不计算日志行 |
pino-pretty@13 | 相当产出 log.js 在dev中(没有它就掉回JSON) |
mongodb@6 | mongo.js, (中文(简体) ), locks.js, (中文(简体) ), upgrade-scripts.js |
ws@8 | ws-client.js |
tough-cookie@5 | axios-with-cookies.js, (中文(简体) ), axios-auth.js |
没有根切入点: 以路径导入每个模块 .
模块
| 导入路径 | 说明 |
|---|---|
@data-fair/lib-node/axios.js | Axios 实例, 错误堆栈线索较短, 数据公平 User-Agent数字 : axiosInstance (默认导出, 公开), privateAxiosInstance, (中文(简体) ), axiosBuilder()。 。 。 . |
@data-fair/lib-node/http-agents.js | 保留带有 DNS 检查和Prometheus 度量衡的 HTTP( S) 代理 : httpAgent 编号 : httpsAgent (公共的,SSRF保护),, privateHttpAgent 编号 : privateHttpsAgent。 。 。 . |
@data-fair/lib-node/ssrf.js | 对不使用上述制剂的客户进行SSF检查: resolvePublicAddress(), (中文(简体) ), publicLookup, (中文(简体) ), SsrfError。 。 。 . |
@data-fair/lib-node/axios-with-cookies.js | Axios 实例 tough-cookie 饼干罐. |
@data-fair/lib-node/axios-auth.js | Axios 实例以电子邮件/密码输入简单目录。 只进行整合测试. |
@data-fair/lib-node/log.js | 堆栈的日志: Stdout上的JSON行 (pretty in dev),隐含上下文,度量衡, debug 输出重定向 . |
@data-fair/lib-node/observer.js | 迷你网络服务器曝光普罗米修斯度量衡和CPU/hiap配置. |
@data-fair/lib-node/mongo.js | Mongo 连接包( 默认导出: 一个单通) , 并声明命名索引管理器( s)configure()) (中文(简体) ). |
@data-fair/lib-node/locks.js | 存储在 MongoDB 的分布式锁 locks 以 TTL (默认导出: 单通) 收集 . |
@data-fair/lib-node/upgrade-scripts.js | 一个服务的数据库迁移脚本的运行者 . |
@data-fair/lib-node/events-queue.js | 事件排行榜和向事件服务处发出的通知. |
@data-fair/lib-node/session.js | SessionHandler:读取并验证了简单的-指导会话饼干(JWKS). 用于 @data-fair/lib-express/session.js 和 Nuxt 服务器代码 . |
@data-fair/lib-node/ws-emitter.js | 通过封顶的 MongoDB 收藏发布 Websocket 信件, 由 @data-fair/lib-express/ws-server.js。 。 。 . |
@data-fair/lib-node/ws-client.js | 拥有自动重联和频道订阅的 Websocket 客户端(WsClient, (中文(简体) ), DataFairWsClient) (中文(简体) ). |
@data-fair/lib-node/fs.js | ensureDir(), (中文(简体) ), emptyDir(), (中文(简体) ), exists()。 。 。 . |
@data-fair/lib-node/validation.js | 再出口 @data-fair/lib-validation。 。 。 . |
@data-fair/lib-node/test-spies.js | 测试助手: 回合 // @test:spy(...) 对测试可以进行的事件进行评论 waitFor()。 。 。 . |
届会见 data-fair-session 技能,用于网络锁定 data-fair-ws 技能。 。 。 .
正在发送的 HTTP 请求和 SSRF
默认的axios实例和公共代理拒绝连接到非公共地址(loopback,私人范围,链接-local包括云元数据服务等). 用户可以影响的每个URL都使用它们.
privateAxiosInstance 私人代理人没有这种限制。 只用于来自服务配置的URL(同一基础设施的其他服务).
import axios, { privateAxiosInstance } from '@data-fair/lib-node/axios.js'
await axios.get(userProvidedUrl)
await privateAxiosInstance.get(config.privateDirectoryUrl + '/api/...')
SSRF_PUBLIC_IPS:逗号分离的IP / CIDR 范围以考虑公开,例如自主办实例的内联网数据源,或127.0.0.1,::1在发展环境中.SSRF_PRIVATE_IPS:逗号分离的IP / CIDR 范围以考虑私有,即使它们是公共地址,例如数据库服务器.
若为 HTTP_PROXY, (中文(简体) ), HTTPS_PROXY 或者说 ALL_PROXY (或它们的小写形式)被定义,代理的保护被禁用(它们连接到代理,而不是目标),启动时会记录到警告.
对于不使用这些代理的客户(ftp, sftp, 原始套接字, SDKs...), @data-fair/lib-node/ssrf.js 出口 resolvePublicAddress(host) (检查主机的每个地址并返回要连接的地址)和 publicLookup 联合国 dns.lookup 任意的相容函数 lookup 选项)。 它们应用相同的规则,不会被代理env变量所禁用. publicLookup 不需要 IP 字元: 请检查这些字元 resolvePublicAddress。 。 。 .
见 data-fair-security 技能 对于堆放规则.
日志
任何需要进口的东西都有一个记录器 从未流传过
import log, { withLogContext } from '@data-fair/lib-node/log.js'
log.info('dataset finalized', { datasetId })
log.info('memory deleted', { code: 'agents.memory.delete' })
log.warn('forbidden request', { code: 'forbidden-req', err })
log.alert('admin api key created', { code: 'df.apikeys.createadmin' })
log.error('failed to create mongo index', { code: 'mongo-index-fail', err, collection })
log.init({ service: 'data-fair' }) // optional, defaults to OTEL_SERVICE_NAME
每种方法都有相同的签名 (msg, fields?) 永远不要扔。 不使用皮诺所写的密钥( N)level, (中文(简体) ), time, (中文(简体) ), msg, (中文(简体) ), hostname作为字段名称,它们会在JSON行中被复制.
| 职等 | 使用 | 接收 | 已计数 |
|---|---|---|---|
debug | 通过 debug 模块(见下文) | 仅允许名称空间 DEBUG | 没有 |
info | 正常业务、审计线索 | 永远 | 没有 |
warn | 客户端错误, 可疑但预期的情况 | 永远 | 对 |
alert | 事件并非失败,但应当受到与错误相同的审查(主要是安全) | 永远 | 对 |
error | 只有内部失败, 从来没有客户端出错 | 永远 | 对 |
产出: 在 stdout 上每行有一个 JSON 对象 NODE_ENV=production,否则产出相当可观(LOG_FORMAT=json|pretty (原始内容存档于2017-03-25). overse. 字段 : time, (中文(简体) ), level (标签), msg, (中文(简体) ), hostname, (中文(简体) ), service, (中文(简体) ), code, (中文(简体) ), err,上下文字段,按呼叫字段,以及 trace_id 编号 : span_id 编号 : trace_flags 当 OpenTeleometry 活动时.
代码数字 : code 每行都可以选择。 一定是个 静态字符串 (单位:千美元)mongo-index-fail, (中文(简体) ), df.apikeys.createadmin:从不将ID,主机或其他动态值放入其中,而是去其他字段. 上面写着柜台的标签.
错误:通过他们作为 err 字段。 其序列采用白名单(type, (中文(简体) ), message, (中文(简体) ), stack(原始内容) code, (中文(简体) ), status, (中文(简体) ), cause,以及 method 编号 : url 没有查询字符串来查找轴错误),所以信头,请求配置和被错误所携带的文档内容从不会到达日志. 信件被切换到 1000 个字符( a AxiosRequestError 从反应机构开始).
计量数字 : warn, (中文(简体) ), alert 财务报告和审定财务报表 error 线条递增 df_logs{level, code, host}在过渡期间被折旧并保持: df_internal_error{errorCode} (错误行)和 df_events_log{level, code, host} (代码警告和警戒线).
调试: 继续使用 debug 模块(import Debug from 'debug', (中文(简体) ), DEBUG=ns1,ns2* 和以前一样 何时 log.js ,共享输出 debug 模块重定向到日志中 debug 带行 ns 字段。 第三方图书馆将自己的副本捆绑起来 debug 未重定向.
隐性上下文
当前上下文的字段被添加到每行. session.middleware() 联 合 国 @data-fair/lib-express 每个请求打开上下文 ip, (中文(简体) ), host, (中文(简体) ), userId, (中文(简体) ), userName, (中文(简体) ), accountKey, (中文(简体) ), accountDep, (中文(简体) ), accountName。任何代码都可以为一个范围添加字段:
await withLogContext({ datasetId }, async () => {
// every line logged in here, even deep in the call stack, carries datasetId
})
规则:
- 只有小的不可变值(编号、密钥、短名),永远不会
req、文档或缓冲器:只要瞄准镜还在,它们就留在记忆中, - 在启动时创建长寿命资源(集合、间隔、缓存、队列),在任何范围之外,或将其捕获并将其后行归属于错误的用户,
- 事件听众运行在发送代码的上下文,而不是订阅代码的上下文.
工人线程有自己的背景:通过 getLogContext() 在任务有效载荷中,并用 withLogContext(payload.logContext, ...) 在工人中间.
打开几何
密码里没啥可做的 在Kubernetes一侧激活 OpenTelemeter 操作器自动装置:它的皮诺仪器添加 trace_id, (中文(简体) ), span_id 财务报告和审定财务报表 trace_flags 到线,和 traceparent 在发出HTTP(包括第三方)的电话时,宣传标题。 设定 OTEL_LOGS_EXPORTER=none 因此,木材不会通过OTLP运输。 没有操作员(dev,测试,脚本)行没有痕量字段.
移徙
| 在此之前 | 之后 |
|---|---|
eventsLog.info(code, msg, ctx) | log.info(msg, { code }) |
eventsLog.warn(code, msg, ctx) | log.warn(msg, { code }) |
eventsLog.alert(code, msg, ctx) | log.alert(msg, { code }) |
internalError(code, err) | log.error(msg, { code, err }) |
console.log 编号 : console.warn 编号 : console.error | log.info 编号 : log.warn 编号 : log.error 带有代码 |
EVENTS_LOG_LEVEL | 删除, 除调试的每个关卡都会放出 |
import Debug from 'debug' | 不变 |
用户、账户、 ip 和主机 eventsLog'上下文论点现在来自隐含上下文.
观察员
默认情况下, 在端口 9090 上, 一个非常轻的可观察性网络服务器 :
GET /metrics这个过程的普罗米修斯度量衡,GET /service-metrics(或/global-metrics: 登记在servicePromRegistry, (中文(简体) ),GET /cpu-profile, (中文(简体) ),/heap-profile, (中文(简体) ),/heap-profile-all(可选)?duration=毫秒,默认为2000年:样本剖面图,GET /heap-snapshot: 完整保留了堆积快照(在V8走堆积时阻断事件循环).
import { startObserver, stopObserver } from '@data-fair/lib-node/observer.js'
await startObserver() // or startObserver(port)
// ...
await stopObserver()
流程衡量标准是简单的 prom-client 度量衡。 服务级的衡量标准(其价值取决于共享状态,如数据库,而不是当前进程的活动)在 servicePromRegistry数字 :
import { Gauge } from 'prom-client'
import { servicePromRegistry } from '@data-fair/lib-node/observer.js'
new Gauge({
name: 'df_my_gauge',
help: '...',
registers: [servicePromRegistry],
async collect () {
this.set(await db.collection('my-collection').estimatedDocumentCount())
}
})
升级脚本
脚本居住于 upgrade/<last-released-version>/ 服务目录 。 文件夹名称必须是版本 上次发布 在编出脚本时,从没有预期的未来版本.
启动时, 运行者读取存储在 services Mongo 收藏, 运行文件夹版本为 >= 然后存储当前 package.json 版本。 因此,一个脚本运行一次 生产升级 和重新运行 在每一个中调部署 直到下一个释放船.
脚本必须是一能的:每个脚本应该运行一次,但是这不能严格保证(当前被套接字,崩溃,手动重跑,取名错误的文件夹),所以再次运行它必须是无操作,而不是失败.
脚本是一个模块,默认导出随 UpgradeScript 接口 :
import type { UpgradeScript } from '@data-fair/lib-node/upgrade-scripts.js'
export default {
description: 'Add a default status to items',
async exec (db, debug) {
await db.collection('items').updateMany({ status: { $exists: false } }, { $set: { status: 'active' } })
}
} as UpgradeScript
在服务初始化期间运行( 运行者使用 upgrade 锁定, 因此只有一个进程运行它们 :
import upgradeScripts from '@data-fair/lib-node/upgrade-scripts.js'
import locks from '@data-fair/lib-node/locks.js'
await locks.start(db)
await upgradeScripts(db, locks) // optional: basePath = './', isFresh callback
这个 upgrade-scripts 技能 详细覆盖文件夹命名规则,同位素模式和新安装.