Skip to main content

very sharp color display,monkey patch bulitin print and high-performance multiprocess safe roating file handler,other handlers includeing dintalk ,email,kafka,elastic and so on

Project description

1.nb_log 简介

nb_log readthedocs文档链接

nb_log 源码链接

image.png

文中文档较长,但其中大部分不是 讲解nb_log 的用法,是复习内置logging的概念。 是由于python人员不懂logging包的日志命名空间和python日志树形命名空间结构,不懂handlers和logger的关系是什么。 所以需要很长的篇幅。

很多pythoner到现在都不知道python的 logging.getLogger() 第一个入参的意义和作用,造成nb_log也不知道怎么使用多命名空间。

1.0 nb_log 安装

pip install nb_log

1.1 nb_log 简单使用例子

print('导入nb_log之前的print是普通的')

from nb_log import get_logger

logger = get_logger('lalala',)   # get_logger 只有一个name是必传递的,其他的参数不是必传。
# logger = get_logger('lalala',log_filename='lalala.log',formatter_template=5,log_file_handler_type=2) # get_logger有很多其他入参可以自由定制logger。


logger.debug(f'debug是绿色,说明是调试的,代码ok ')
logger.info('info是天蓝色,日志正常 ')
logger.warning('黄色yello,有警告了 ')
logger.error('粉红色说明代码有错误 ')
logger.critical('血红色,说明发生了严重错误 ')

print('导入nb_log之后的print是强化版的可点击跳转的')

1.1.b nb_log 的最核心函数 get_logger入参说明

   :param name: 日志命名空间,意义非常非常非常重要,有些人到现在还不知道 logging.getLogger() 第一个入参的作用,太low了。不同的name的logger可以表现出不同的行为。
                例如让 aa命名空间的日志打印控制台并且写入到文件,并且只记录info级别以上,让 bb 命名空间的日志仅仅打印控制台,并且打印debug以上级别,
                这种就可以通过不同的日志命名空间做到。
   :param log_level_int: 日志输出级别,设置为 1 2 3 4 5,分别对应原生logging.DEBUG(10),logging.INFO(20),
          logging.WARNING(30),logging.ERROR(40),logging.CRITICAL(50)级别,现在可以直接用10 20 30 40 50了,兼容了。

   :param is_add_stream_handler: 是否打印日志到控制台,默认会打印控制台。
   :param do_not_use_color_handler :是否禁止使用color彩色日志
   :param log_path: 设置存放日志的文件夹路径,如果不设置,则取nb_log_config.LOG_PATH,如果配置中也没指定则自动在代码所在磁盘的根目录创建/pythonlogs文件夹,
          非windwos下要注意账号权限问题(如果python没权限在根目录建/pythonlogs,则需要手动先创建好)
   :param log_filename: 日志的名字,仅当log_path和log_filename都不为None时候才会写入到日志文件。用户不指定 log_filename 默认当作用户不希望把日志写入到文件中。
   :param log_file_size :日志大小,单位M,默认100M
   :param log_file_handler_type :这个值可以设置为 1 2 3 4 5 五种值,1为使用多进程安全按日志文件大小切割的文件日志,
          2为多进程安全按天自动切割的文件日志,同一个文件,每天生成一个日志
          3为不自动切割的单个文件的日志(不切割文件就不会出现所谓进程安不安全的问题)
          4为 WatchedFileHandler,这个是需要在linux下才能使用,需要借助lograte外力进行日志文件的切割,多进程安全。
          5 为第三方的concurrent_log_handler.ConcurrentRotatingFileHandler按日志文件大小切割的文件日志,
            这个是采用了文件锁,多进程安全切割,文件锁在linux上使用fcntl性能还行,win上使用win32con性能非常惨。按大小切割建议不要选第5个个filehandler而是选择第1个。
   :param mongo_url : mongodb的连接,为None时候不添加mongohandler
   :param is_add_elastic_handler: 是否记录到es中。
   :param is_add_kafka_handler: 日志是否发布到kafka。
   :param ding_talk_token:钉钉机器人token
   :param ding_talk_time_interval : 时间间隔,少于这个时间不发送钉钉消息
   :param mail_handler_config : 邮件配置
   :param is_add_mail_handler :是否发邮件
   :param formatter_template :日志模板,如果为数字,则为nb_log_config.py字典formatter_dict的键对应的模板,
                            1为formatter_dict的详细模板,2为简要模板,5为最好模板。
                            如果值为logging.Formatter对象,则直接使用用户传入的模板,不从formatter_dict中选择模板。
 
   

log_filename 用于设置是否写入日志文件和写入什么文件中。有的人不看入参文档,就问nb_log为什么不写入日志文件中。 logger和handler是观察者模式,日志记录到哪些地方,是由添加了什么handlers决定的。

1.1.c nb_log配置文件的生成和导入。

项目中任意脚本使用nb_log,第一次运行代码时候,会自动在 sys.path[1] 目录下创建 nb_log_config.py文件并写入默认值。 之后nb_log 会自动 import nb_log_config, 如果import到这个模块了,控制台会提示读取了什么文件作为配置文件。

如果是 cmd或者linux运行不是pycharm,需要 设置 PYTHONPATH为项目根目录,这样就能自动在当前项目根目录下生成或者找到 nb_log_config.py了。

用户可以print(sys.path) print(sys.path[1]) 来查看 sys.path[1]的值是什么就知道了。

连PYTHONPATH作用是什么都不知道的python小白,一定要看下面文章 。

pythonpath作用介绍的文章

1.1.d nb_log配置文件的一些参数说明。

DEFAULUT_USE_COLOR_HANDLER = True  # 是否默认使用有彩的日志。
DISPLAY_BACKGROUD_COLOR_IN_CONSOLE = True  # 在控制台是否显示彩色块状的日志。为False则不使用大块的背景颜色。
AUTO_PATCH_PRINT = True  # 是否自动打print的猴子补丁,如果打了猴子补丁,print自动变色和可点击跳转。
SHOW_PYCHARM_COLOR_SETINGS = True  # 有的人很反感启动代码时候提示教你怎么优化pycahrm控制台颜色,可以把这里设置为False

DEFAULT_ADD_MULTIPROCESSING_SAFE_ROATING_FILE_HANDLER = False  # 是否默认同时将日志记录到记log文件记事本中,就是用户不指定 log_filename的值,会自动写入日志命名空间.log文件中。
LOG_FILE_SIZE = 100  # 单位是M,每个文件的切片大小,超过多少后就自动切割
LOG_FILE_BACKUP_COUNT = 14  # 对同一个日志文件,默认最多备份几个文件,超过就删除了。

LOG_PATH = '/pythonlogs'  # 默认的日志文件夹,如果不写明磁盘名,则是项目代码所在磁盘的根目录下的/pythonlogs
# LOG_PATH = Path(__file__).absolute().parent / Path("pythonlogs")   #这么配置就会自动在你项目的根目录下创建pythonlogs文件夹了并写入。
if os.name == 'posix':  # linux非root用户和mac用户无法操作 /pythonlogs 文件夹,没有权限,默认修改为   home/[username]  下面了。例如你的linux用户名是  xiaomin,那么默认会创建并在 /home/xiaomin/pythonlogs文件夹下写入日志文件。
    home_path = os.environ.get("HOME", '/')  # 这个是获取linux系统的当前用户的主目录,不需要亲自设置
    LOG_PATH = Path(home_path) / Path('pythonlogs')  # linux mac 权限很严格,非root权限不能在/pythonlogs写入,修改一下默认值。

LOG_FILE_HANDLER_TYPE = 1  # 1 2 3 4 5
"""
LOG_FILE_HANDLER_TYPE 这个值可以设置为 1 2 3 4 5 四种值,
1为使用多进程安全按日志文件大小切割的文件日志,这是本人实现的批量写入日志,减少操作文件锁次数,测试10进程快速写入文件,win上性能比第5种提高了100倍,linux提升5倍
2为多进程安全按天自动切割的文件日志,同一个文件,每天生成一个新的日志文件。日志文件名字后缀自动加上日期。
3为不自动切割的单个文件的日志(不切割文件就不会出现所谓进程安不安全的问题) 
4为 WatchedFileHandler,这个是需要在linux下才能使用,需要借助lograte外力进行日志文件的切割,多进程安全。
5 为第三方的concurrent_log_handler.ConcurrentRotatingFileHandler按日志文件大小切割的文件日志,
   这个是采用了文件锁,多进程安全切割,文件锁在linux上使用fcntl性能还行,win上使用win32con性能非常惨。按大小切割建议不要选第5个个filehandler而是选择第1个。
"""

以上只是部分配置的例子,其他配置在你项目根目录下的 nb_log_config.py中都有默认值,自己按需修改设置。 其他例如日志模板定义,默认日志模板选择什么,都可以在 nb_log_config.py文件中设置。

1.1.1e 日志配置文件和get_logger传参的关系。

nb_log_config.py中是设置全局设置,get_logger是针对单个logger对象生成的设置。

例如 nb_log_config.py 中写 FORMATTER_KIND = 4,get_logger 传参 formatter_template=6,那么最终还是使用第6个日志模板。 如果get_logger函数没有传参指定就使用 nb_log_config.py中的配置。 就是说 get_logger 是优先级高的,nb_log_config.py 是优先级低的配置方式。

1.2 nb_log功能介绍

1.2.1 nb_log 支持日志根据级别自动变彩色

如图:日志彩色符合交通灯颜色认知。绿色是debug等级的日志,天蓝色是info等级日志, 黄色是warnning等级的警告日志,粉红色是error等级的错误日志,血红色是criticl等级的严重错误日志

1.2.1b 设置是否需要彩色

nb_log支持自动彩色,也支持关闭背景色块只要颜色,也支持彻底不要颜色所有日志显示为正常黑白颜色。

可以在你项目根目录下自动生成的nb_log_config.py配置文件中修改相关配置,来控制是否需要颜色,或者要颜色但不要大块的背景色块。

如果反对日志有各种彩色,可以设置 DEFAULUT_USE_COLOR_HANDLER = False
如果反对日志有块状背景彩色,可以设置 DISPLAY_BACKGROUD_COLOR_IN_CONSOLE = False
如果想屏蔽nb_log包对怎么设置pycahrm的颜色的提示,可以设置 WARNING_PYCHARM_COLOR_SETINGS = False
如果想改变日志模板,可以设置 FORMATTER_KIND 参数,只带了7种模板,可以自定义添加喜欢的模板
LOG_PATH 配置文件日志的保存路径的文件夹。

1.2.1c 关于彩色显示效果的最终显示的说明

有的人听说了python显示颜色的博客,例如这种

python print显示颜色

python在控制台可以同时显示7种颜色,但是同时显示不出来65536种颜色,pycahrm控制台/win cmd/linux的控制台终端不是浏览器网页,不能显示丰富的65536色模式,
只能暴露7种ansi颜色钩子,显示控制台输出的终端软件一般提供了颜色的自定义设置,例如 pycahrm finashell xhsell
这些软件都可以对ansi颜色自定义65536色模式的颜色代码,
例如nb_log启动时候就打印提示了教用户怎么设置颜色。

例如一件拍摄街道的彩色相片有60多种颜色,在cmd pycahrm终端是不可能同时显示出那么多种颜色的。
例如你想要控制台显示杨幂穿的淡红色衣服的颜色,控制台能做得到吗?当然是能做到得,但不是在python种 用所谓得  \033[ 来设置颜色,
因为软件终端只能识别7种ansi颜色钩子,红色在65536色模式下最起码也有几万种颜色代码,有白浅红色 水红色 大红色 粉红色 红的发紫的红色 红得发黑的红色,
所以你想精确得让控制台显示多种不同的红色,你自己用大脑想想呗,仅仅在python print中 \033就想得到理想的所需的红色,简直是做梦吧。
我说的是要精确控制颜色,不能光靠python的\033[,而是要在python的终端输出软件中设置颜色。例如pycharm xhsell finashell软件中都支持自定义颜色。

所以有些小白用户觉得颜色不好看,让我在配置文件中放开自定义颜色,这是不可行的,颜色最终的显示效果由控制台终端决定,不是所谓的\033能决定的,
例如我就想问  \033后面加什么字母能精确得到桃红色 金黄色 亮绿色这些 ,这么简单的想不到吗?如果控制台自动支持65536种颜色同时显示,那么nb_log可以暴露出来怎么配置颜色。
例如  \033[32  是绿色,但是软件终端中重定义ansi 颜色,可以让你代码的\033[32 显示出1万种不同的绿色,当然也可以让\033[32 绿色但是显示成黄色 紫色啥的,
因为最终渲染颜色效果是由终端决定,不是代码中\033后面数字来决定的。用户需要在软件终端中重新定义颜色,拿pycahrm为例,设置各种想要的颜色30秒钟,配置颜色要不了很久。

1.2.1d pycharm中精确设置控制台颜色的方式

要说明的是,即使是同一个颜色代码在pycahrm不同主题都是颜色显示区别很大的,默认的可能很丑或者由于颜色不好导致文字看不清晰
为了达到我这种色彩效果需要重新设置主题颜色,在控制台输出的第一行就教大家怎么设置颜色了。
也可以按下面设置,需要花30秒设置。


1)使用pycharm时候,建议重新自定义设置pycharm的console里面的主题颜色。
设置方式为 打开pycharm的 file -> settings -> Editor -> Color Scheme -> Console Colors 选择monokai,
并重新修改自定义7个颜色,设置Blue为 0454F3 ,Cyan为 04DCF8 ,Green 为 13FC02 ,Magenta为 ff1cd5 ,red为 F80606 ,yellow为 EAFA04 ,gray 为 FFFFFF ,white 为 FFFFFF 。
如果设置为显示背景色快,由于不同版本的pycahrm或主题,可以根据控制台实际显示设置 White 为 1F1F1F, Black 为 FFFFFF,因为背景色是深色,前景色的文字设置为白色比黑色好。

2)使用xshell或finashell工具连接linux也可以自定义主题颜色,默认使用shell连接工具的颜色也可以。

1.2.2 nb_log 不仅支持日志变彩色,还支持项目中所有python文件的任意print自动变彩色

导入nb_log时候会给内置的 ptint 打猴子补丁,所以用户所有地方的print行为自动发生了变化,重定向到nb_log定义的print了

1.2.2b print自动化效果转换的好处说明

自动转换print效果,再也不怕有人在项目中随意print,导致很难找到是从哪里冒出来的print。
只要import nb_log,项目所有地方的print自动现型并在控制台可点击几精确跳转到print的地方。

在项目里面的几百个文件中疯狂print真的让人很生气,一个run.py运行起来几百个py文件,
每个文件print 七八次,到底自己想看想关心的print是在控制台的哪一行呢,找到老眼昏花都找不到。
比如打印x变量的值,有人是为了省代码直接 print(x),而没有多打几个字母使用print("x的值是:",x),
这样打印出来的x变量,根本无法通过全局查找找到打印x变量是在什么py文件的哪一行。

有人说把之前的print全部用#注释不就好了,那这要全局找找print,一个一个的修改,一个10万行项目, 
就算平均100行有一个print关键字,那起码也得有1000个print关键字吧,一个个的修改那要改到猴年马月呢。

只有使用nb_log,才能让一切print妖魔鬼怪自动现形。

另外,在正式项目或工具类甚至做得包里面,疯狂print真的很low,可以参考大神的三方包,从来都没直接print的不存在的,
他们都是用的日志。
日志比print灵活多了,对命名空间的控制、级别过滤控制、模板自定义、能记录到的地方扩展性很强远强过print的只有控制台。

1.2.2c nb_log 五彩日志的效果截图

image.png

1.3 nb_log 支持pycharm控制台点击日志精确跳转到打印日志的文件和行号

8tka3.png

1.4 nb_log是原生logging类型,兼容性 扩展性非常好。

nb_log 是基于python自带的原生logging模块封装的, nb_log.get_logger()生成的日志类型是 原生logging.Logger类型, 所以nb_log包对常用三方包日志兼容性替换芯做到了100%。是否是原生日志非常重要,logbook和loguru都不是python自带的原生日志, 所以和三方包结合或者替换性不好。

比如logru和logbook这种三方库,完全重新写的日志,
它里面主要被用户使用的logger变量类型不是python内置Logger类型,
造成logger说拥有的属性和方法有的不存在或者不一致,这样的日志和python内置的经典日志兼容性差,
只能兼容(一键替换logger类型)一些简单的debug info warning errror等方法,。

1.5 nb_log 能够简单讲日志记录到十几种地方的任意几种的组合。

内置了一键入参,每个参数是独立开关,可以把日志同时记录到10几个常用的地方的任意几种组合, 包括 控制台 文件 钉钉 邮件 mongo kafka es 等等 。

有的人以为日志只能记录到控制台和文件,其实是错的,日志可以记录到很多种地方,日志记录到哪里,是由logger添加了什么handler决定的。

1.6 日志命名空间独立,采用了多实例logger,按日志命名空间区分。

"""
命名空间独立意味着每个logger单独的日志界别过滤,单独的控制要记录到哪些地方。
"""

from nb_log import get_logger, LogManager

logger_aa = LogManager('aa').get_logger_and_add_handlers(10, log_filename='aa.log')
logger_bb = get_logger("bb", log_level_int=30, is_add_stream_handler=False, ding_talk_token='your_dingding_token')
logger_cc = get_logger('cc', log_level_int=10, log_filename='cc.log')

logger_aa.debug('哈哈哈')
# 将会同时记录到控制台和文件aa.log中,只要debug及debug以上级别都会记录。

logger_bb.warning('嘿嘿嘿')
# 将只会发送到钉钉群消息,并且logger_bb的info debug级别日志不会被记录,非常方便测试调试然后稳定了调高界别到生产。

logger_cc.debug('嘻嘻')
# logger_cc的日志会写在cc.log中,和logger_aa的日志是不同的文件。

1.7 对内置looging包打了猴子补丁,使日志永远不会使用同种handler重复记录 ,例如,原生的

from logging import getLogger,StreamHandler
logger = getLogger('hi')
getLogger('hi').addHandler(StreamHandler())
getLogger('hi').addHandler(StreamHandler())
getLogger('hi').addHandler(StreamHandler())
logger.warning('啦啦啦')

明明只warning了一次,但实际会造成 啦啦啦 在控制台打印3次。
使用nb_log,对同一命名空间的日志,可以无惧反复添加同类型handler,不会重复记录。

关于重复记录的例子,更惨的例子在文档后面的例子,直接把机器cpu性能耗尽,磁盘弄爆炸。

1.8 nb_log使用对比原生logging和 loguru 更简单

1.8.1 logging 代码方式创建logger对象

import logging
logger = logging.getLogger('my.logger.namespace')

fh = logging.FileHandler('test.log')  # 可以向文件发送日志

ch = logging.StreamHandler()  # 可以向屏幕发送日志

fm = logging.Formatter('%(asctime)s %(message)s')  # 打印格式

fh.setFormatter(fm)
ch.setFormatter(fm)

logger.addHandler(fh)
logger.addHandler(ch)
logger.setLevel(logging.DEBUG)  # 设置级别


logger.debug('debug 喜喜')

有些人简直是怕了原生logging了,为了创建一个好用的logger对象,代码步骤复杂的吓人,很多人完全没看懂这段代码意义, 因为他是一步步创建观察者handler,给handler设置好看的formattor,给给被观察者添加多个观察者对象。 大部分人不看设计模式,不仅不懂观察者模式,而且没听说观察者模式,所以这种创建logger方式完全蒙蔽的节奏。 其实这样一步步的写代码是为了给用户最大的自由来怎么创建一个所需的logger对象。如果高度封装创建logger过程那是简单了, 但是自定义自由度就下降了。 logging是原生日志,每个三方包肯定使用logging了,为了兼容性和看懂三方包,那肯定是要学习logging的,对logging望而却步, 想投机取巧只使用loguru是行不通的,三方包不会使用loguru,三方包里面各种命名空间的日志,等待用户添加handlers来记录日志, loguru缺点太大了。

nb_log把logging创建logger封装了,但同时get_logger暴露了很多个入参,来让用户自由自定义logger添加什么handler和设置什么formattor。 所以nb_log有原生logging的普遍兼容性,又使用简单

1.8.2 python中 创建logger的第二种方式,logging.config.dictConfig()

import logging
import logging.config
 
LOGGING_CONFIG = {
    "version": 1,
    "formatters": {
        "default": {
            'format':'%(asctime)s %(filename)s %(lineno)s %(levelname)s %(message)s',
        },
        "plain": {
            "format": "%(message)s",
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "INFO",
            "formatter": "default",
        },
        "console_plain": {
            "class": "logging.StreamHandler",
            "level":logging.INFO,
            "formatter": "plain"
        },
        "file":{
            "class": "logging.FileHandler",
            "level":20,
            "filename": "./log.txt",
            "formatter": "default",
        }
    },
    "loggers": {
        "console_logger": {
            "handlers": ["console"],
            "level": "INFO",
            "propagate": False,
        },
        "console_plain_file_logger": {
            "handlers": ["console_plain","file"],
            "level": "DEBUG",
            "propagate": False,
        },
        "file_logger":{
            "handlers": ["file"],
            "level": "INFO",
            "propagate": False,
        }
    },
    "disable_existing_loggers": True,
}
 
# 运行测试
logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("console_logger")
logger.debug('debug message')
logger.info('info message')
logger.warn('warning message')
logger.error('error message')
logger.critical('critical message')

这种方式和上面1.8.1的方式差不多, 但不需要写大量python代码来创建logger对象。 虽然不需要写大量python代码来构建logger对象,但是需要写 LOGGING_CONFIG 字典, 这种字典如果写错了导致配置不生效或者报错,还是很麻烦的。很多人对这个配置完全蒙蔽,不知道什么意思。

先创建formattor,创建文件和控制台handler(当然也可以自定义发送钉钉的handler),handler设置日志过滤级别,handler设置formattor, 不同的handler可以设置不同的formattor,例如同样是 logger.debug("hello world"),可以使文件和控制台记录的这条日志的前缀和字段不一样。

对不同命名空间的logger添加不同的handlers, 例如你只想打印控制台 就 logger = logging.getLogger("console_logger"),然后用这个logger.info(xxx)就可以打印控制台了。 例如你只想打写入文件 就 logger = logging.getLogger("file_logger"),然后用这个logger.info(xxx)就可以打印控制台了。 例如你打写入文件并且打印控制台 就 logger = logging.getLogger("console_plain_file_logger"),然后用这个logger.info(xxx)就可以打印控制台并且同时写入文件了。

对1.8.1和1.8.2不理解造成恐惧,是使大家使用loguru的主要原因。

1.8.3 loguru的简单使用

from loguru import logger
logger.add("./log_files/loguru-test1.log",  rotation="100000 KB")
logger.info("hello")
代码是loguru打印控制台和写入文件,和nb_log一样代码少。
甚至如果用户不需要写入文件只需要导入logger就好了,

from loguru import logger
logger.info("hello")

看起来很简单,nb_log还需要 get_logger一下,有的人觉得loguru少写一行代码,直接import就能使用了,所以loguru简单牛逼。
nb_log早就知道有人会这么想了,nb_log也支持导入即可使用。

from nb_log import defaul_logger
defaul_logger.info("hello")

但这样有个弊端,用户想使用什么日志模板,用户希望日志记录到 控制台 文件 钉钉 es中的哪几个地方没法定义。
用户如果想屏蔽a函数里面的日志,但想放开b函数里面的日志,这种不传参/不设置日志命名空间的日志就无能为力做到了。
所以nb_log推荐用户调用get_logger函数来自定义日志,而不是直接import defaul_logger然后所有地方都使用这个 defaul_logger来记录日志。

综上所述 nb_log既使用简单,又兼容性高。

1.9 内置logging包的日志命名空间是什么

import logging
logger1 = logging.getLogger('aaa')

logger2 = logging.getLogger('aaa')

logger3 = logging.getLogger('bbb')

print('logger1 id: ',id(logger1),'logger2 id: ',id(logger2),'logger3 id: ',id(logger3))

运行上面可以发现 logger1和logger2对象是同一个id,logger3对象是另外一个id。 通过不同的日志命名空间,可以设置不同级别的日志显示,设置不同类型的日志记录到不同的文件,是否打印控制台,是否发送邮件 钉钉消息。

有的人到现在还是不知道日志命名空间的作用,对一个大项目的所有的日志只会处理成一种表现行为,悲了个剧。

1.10 nb_log比logurur有10胜

nb_log比logurur有10个优点方面

1.20 完整readthedocs文档地址

nb_log readthedocs文档链接

nb_log 源码链接

Project details


Release history Release notifications | RSS feed

This version

9.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nb_log-9.0.tar.gz (59.2 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page