[{"data":1,"prerenderedAt":1114},["ShallowReactive",2],{"docs-page-\u002Fdocs\u002Fpython":3,"docs-surround-\u002Fdocs\u002Fpython":1105},{"id":4,"title":5,"body":6,"description":1098,"extension":1099,"meta":1100,"navigation":119,"path":1101,"seo":1102,"stem":1103,"__hash__":1104},"docs\u002Fdocs\u002F03.python.md","Python",{"type":7,"value":8,"toc":1085},"minimark",[9,13,31,36,61,80,84,234,244,257,263,272,451,468,473,480,605,611,615,718,728,732,735,862,885,889,1026,1030,1040,1060,1063,1067,1081],[10,11,5],"h1",{"id":12},"python",[14,15,16,20,21,26,27,30],"p",{},[17,18,19],"code",{},"lumber-cloud"," is Lumber's Python client. It encrypts every log with ",[22,23,25],"a",{"href":24},"\u002Fdocs\u002Fencryption","AES-256-GCM"," before it leaves your process, and it plugs into Python's ",[17,28,29],{},"logging",", so the loggers your code and its libraries already use can send to Lumber too.",[32,33,35],"h2",{"id":34},"install","Install",[37,38,43],"pre",{"className":39,"code":40,"language":41,"meta":42,"style":42},"language-bash shiki shiki-themes github-dark","pip install lumber-cloud\n","bash","",[17,44,45],{"__ignoreMap":42},[46,47,50,54,58],"span",{"class":48,"line":49},"line",1,[46,51,53],{"class":52},"svObZ","pip",[46,55,57],{"class":56},"sU2Wk"," install",[46,59,60],{"class":56}," lumber-cloud\n",[14,62,63,64,72,73,75,76,79],{},"Python 3.9 or later. Its one dependency is ",[22,65,69],{"href":66,"rel":67},"https:\u002F\u002Fcryptography.io",[68],"nofollow",[17,70,71],{},"cryptography",". The package is ",[17,74,19],{}," on PyPI, and you import it as ",[17,77,78],{},"lumber_cloud",".",[32,81,83],{"id":82},"quick-start","Quick start",[37,85,88],{"className":86,"code":87,"language":12,"meta":42,"style":42},"language-python shiki shiki-themes github-dark","import os\nimport lumber_cloud as lumber\n\nlumber.config(api_key=os.environ[\"LUMBER_API_KEY\"])\n\nlumber.info(\"Server started\", port=8000)\nlumber.warn(\"Rate limit approaching\", request_id=\"req-123\", user_id=456)\nlumber.error(\"Payment failed\", trace_id=\"trace-abc\", order_id=789)\n",[17,89,90,100,114,121,143,148,172,203],{"__ignoreMap":42},[46,91,92,96],{"class":48,"line":49},[46,93,95],{"class":94},"snl16","import",[46,97,99],{"class":98},"s95oV"," os\n",[46,101,103,105,108,111],{"class":48,"line":102},2,[46,104,95],{"class":94},[46,106,107],{"class":98}," lumber_cloud ",[46,109,110],{"class":94},"as",[46,112,113],{"class":98}," lumber\n",[46,115,117],{"class":48,"line":116},3,[46,118,120],{"emptyLinePlaceholder":119},true,"\n",[46,122,124,127,131,134,137,140],{"class":48,"line":123},4,[46,125,126],{"class":98},"lumber.config(",[46,128,130],{"class":129},"s9osk","api_key",[46,132,133],{"class":94},"=",[46,135,136],{"class":98},"os.environ[",[46,138,139],{"class":56},"\"LUMBER_API_KEY\"",[46,141,142],{"class":98},"])\n",[46,144,146],{"class":48,"line":145},5,[46,147,120],{"emptyLinePlaceholder":119},[46,149,151,154,157,160,163,165,169],{"class":48,"line":150},6,[46,152,153],{"class":98},"lumber.info(",[46,155,156],{"class":56},"\"Server started\"",[46,158,159],{"class":98},", ",[46,161,162],{"class":129},"port",[46,164,133],{"class":94},[46,166,168],{"class":167},"sDLfK","8000",[46,170,171],{"class":98},")\n",[46,173,175,178,181,183,186,188,191,193,196,198,201],{"class":48,"line":174},7,[46,176,177],{"class":98},"lumber.warn(",[46,179,180],{"class":56},"\"Rate limit approaching\"",[46,182,159],{"class":98},[46,184,185],{"class":129},"request_id",[46,187,133],{"class":94},[46,189,190],{"class":56},"\"req-123\"",[46,192,159],{"class":98},[46,194,195],{"class":129},"user_id",[46,197,133],{"class":94},[46,199,200],{"class":167},"456",[46,202,171],{"class":98},[46,204,206,209,212,214,217,219,222,224,227,229,232],{"class":48,"line":205},8,[46,207,208],{"class":98},"lumber.error(",[46,210,211],{"class":56},"\"Payment failed\"",[46,213,159],{"class":98},[46,215,216],{"class":129},"trace_id",[46,218,133],{"class":94},[46,220,221],{"class":56},"\"trace-abc\"",[46,223,159],{"class":98},[46,225,226],{"class":129},"order_id",[46,228,133],{"class":94},[46,230,231],{"class":167},"789",[46,233,171],{"class":98},[14,235,236,237,240,241,243],{},"Call ",[17,238,239],{},"config()"," once at startup; every module that imports ",[17,242,78],{}," then logs with the same client. Logs are sent from a background thread, so logging never waits on the network, and logs still queued when your program exits get up to 5 seconds to send.",[14,245,246,247,251,252,256],{},"The API key comes from the Lumber app (see ",[22,248,250],{"href":249},"\u002Fdocs\u002Fgetting-started#create-an-app-in-lumber","Getting Started","). Keep it in an environment variable or your secrets manager, never in source control, and never in an app or game you ship to people (",[22,253,255],{"href":254},"\u002Fdocs\u002Fapi-keys#keep-the-key-on-your-servers","why",").",[32,258,260,261],{"id":259},"with-logging","With ",[17,262,29],{},[14,264,265,268,269,271],{},[17,266,267],{},"LumberHandler"," sends records from Python's ",[17,270,29],{}," to Lumber:",[37,273,275],{"className":86,"code":274,"language":12,"meta":42,"style":42},"import logging\nimport os\nfrom lumber_cloud import LumberHandler\n\nlogging.basicConfig(level=logging.INFO)  # keep printing to the console\nlogging.getLogger().addHandler(LumberHandler(os.environ[\"LUMBER_API_KEY\"]))\n\nlog = logging.getLogger(__name__)\nlog.info(\"Report ready in %.1fs\", 2.4, extra={\"request_id\": \"req-123\", \"rows\": 1500})\n\ntry:\n    charge(order)\nexcept PaymentError:\n    log.exception(\"Payment failed\")  # sent at ERROR with the traceback\n",[17,276,277,284,290,302,306,329,339,343,358,409,414,423,429,438],{"__ignoreMap":42},[46,278,279,281],{"class":48,"line":49},[46,280,95],{"class":94},[46,282,283],{"class":98}," logging\n",[46,285,286,288],{"class":48,"line":102},[46,287,95],{"class":94},[46,289,99],{"class":98},[46,291,292,295,297,299],{"class":48,"line":116},[46,293,294],{"class":94},"from",[46,296,107],{"class":98},[46,298,95],{"class":94},[46,300,301],{"class":98}," LumberHandler\n",[46,303,304],{"class":48,"line":123},[46,305,120],{"emptyLinePlaceholder":119},[46,307,308,311,314,316,319,322,325],{"class":48,"line":145},[46,309,310],{"class":98},"logging.basicConfig(",[46,312,313],{"class":129},"level",[46,315,133],{"class":94},[46,317,318],{"class":98},"logging.",[46,320,321],{"class":167},"INFO",[46,323,324],{"class":98},")  ",[46,326,328],{"class":327},"sAwPA","# keep printing to the console\n",[46,330,331,334,336],{"class":48,"line":150},[46,332,333],{"class":98},"logging.getLogger().addHandler(LumberHandler(os.environ[",[46,335,139],{"class":56},[46,337,338],{"class":98},"]))\n",[46,340,341],{"class":48,"line":174},[46,342,120],{"emptyLinePlaceholder":119},[46,344,345,348,350,353,356],{"class":48,"line":205},[46,346,347],{"class":98},"log ",[46,349,133],{"class":94},[46,351,352],{"class":98}," logging.getLogger(",[46,354,355],{"class":167},"__name__",[46,357,171],{"class":98},[46,359,361,364,367,370,373,375,378,380,383,385,388,391,394,396,398,401,403,406],{"class":48,"line":360},9,[46,362,363],{"class":98},"log.info(",[46,365,366],{"class":56},"\"Report ready in ",[46,368,369],{"class":167},"%.1f",[46,371,372],{"class":56},"s\"",[46,374,159],{"class":98},[46,376,377],{"class":167},"2.4",[46,379,159],{"class":98},[46,381,382],{"class":129},"extra",[46,384,133],{"class":94},[46,386,387],{"class":98},"{",[46,389,390],{"class":56},"\"request_id\"",[46,392,393],{"class":98},": ",[46,395,190],{"class":56},[46,397,159],{"class":98},[46,399,400],{"class":56},"\"rows\"",[46,402,393],{"class":98},[46,404,405],{"class":167},"1500",[46,407,408],{"class":98},"})\n",[46,410,412],{"class":48,"line":411},10,[46,413,120],{"emptyLinePlaceholder":119},[46,415,417,420],{"class":48,"line":416},11,[46,418,419],{"class":94},"try",[46,421,422],{"class":98},":\n",[46,424,426],{"class":48,"line":425},12,[46,427,428],{"class":98},"    charge(order)\n",[46,430,432,435],{"class":48,"line":431},13,[46,433,434],{"class":94},"except",[46,436,437],{"class":98}," PaymentError:\n",[46,439,441,444,446,448],{"class":48,"line":440},14,[46,442,443],{"class":98},"    log.exception(",[46,445,211],{"class":56},[46,447,324],{"class":98},[46,449,450],{"class":327},"# sent at ERROR with the traceback\n",[14,452,453,454,457,458,460,461,463,464,467],{},"Each record becomes a log at the matching level (CRITICAL is FATAL), with its arguments filled into its message. ",[17,455,456],{},"extra="," keys go into the log's metadata, except ",[17,459,185],{}," and ",[17,462,216],{},", which are the log's own fields, and ",[17,465,466],{},"context",", which goes into its context. The logger's name, file, line and function go into the context too.",[469,470,472],"h3",{"id":471},"django","Django",[14,474,475,476,479],{},"Add the handler to ",[17,477,478],{},"LOGGING"," in your settings:",[37,481,483],{"className":86,"code":482,"language":12,"meta":42,"style":42},"LOGGING = {\n    \"version\": 1,\n    \"handlers\": {\n        \"lumber\": {\n            \"class\": \"lumber_cloud.LumberHandler\",\n            \"api_key\": os.environ[\"LUMBER_API_KEY\"],\n            \"level\": \"INFO\",\n        },\n    },\n    \"root\": {\"handlers\": [\"lumber\"], \"level\": \"INFO\"},\n}\n",[17,484,485,495,508,516,523,535,548,560,565,570,600],{"__ignoreMap":42},[46,486,487,489,492],{"class":48,"line":49},[46,488,478],{"class":167},[46,490,491],{"class":94}," =",[46,493,494],{"class":98}," {\n",[46,496,497,500,502,505],{"class":48,"line":102},[46,498,499],{"class":56},"    \"version\"",[46,501,393],{"class":98},[46,503,504],{"class":167},"1",[46,506,507],{"class":98},",\n",[46,509,510,513],{"class":48,"line":116},[46,511,512],{"class":56},"    \"handlers\"",[46,514,515],{"class":98},": {\n",[46,517,518,521],{"class":48,"line":123},[46,519,520],{"class":56},"        \"lumber\"",[46,522,515],{"class":98},[46,524,525,528,530,533],{"class":48,"line":145},[46,526,527],{"class":56},"            \"class\"",[46,529,393],{"class":98},[46,531,532],{"class":56},"\"lumber_cloud.LumberHandler\"",[46,534,507],{"class":98},[46,536,537,540,543,545],{"class":48,"line":150},[46,538,539],{"class":56},"            \"api_key\"",[46,541,542],{"class":98},": os.environ[",[46,544,139],{"class":56},[46,546,547],{"class":98},"],\n",[46,549,550,553,555,558],{"class":48,"line":174},[46,551,552],{"class":56},"            \"level\"",[46,554,393],{"class":98},[46,556,557],{"class":56},"\"INFO\"",[46,559,507],{"class":98},[46,561,562],{"class":48,"line":205},[46,563,564],{"class":98},"        },\n",[46,566,567],{"class":48,"line":360},[46,568,569],{"class":98},"    },\n",[46,571,572,575,578,581,584,587,590,593,595,597],{"class":48,"line":411},[46,573,574],{"class":56},"    \"root\"",[46,576,577],{"class":98},": {",[46,579,580],{"class":56},"\"handlers\"",[46,582,583],{"class":98},": [",[46,585,586],{"class":56},"\"lumber\"",[46,588,589],{"class":98},"], ",[46,591,592],{"class":56},"\"level\"",[46,594,393],{"class":98},[46,596,557],{"class":56},[46,598,599],{"class":98},"},\n",[46,601,602],{"class":48,"line":416},[46,603,604],{"class":98},"}\n",[14,606,607,608,79],{},"To share one client between a handler and your own calls, pass it in: ",[17,609,610],{},"LumberHandler(client=lumber.config(api_key=...))",[32,612,614],{"id":613},"log-methods","Log methods",[616,617,618,631],"table",{},[619,620,621],"thead",{},[622,623,624,628],"tr",{},[625,626,627],"th",{},"Method",[625,629,630],{},"Level",[632,633,634,645,654,667,677,687,700],"tbody",{},[622,635,636,642],{},[637,638,639],"td",{},[17,640,641],{},"debug(message, **data)",[637,643,644],{},"DEBUG",[622,646,647,652],{},[637,648,649],{},[17,650,651],{},"info(message, **data)",[637,653,321],{},[622,655,656,664],{},[637,657,658,159,661],{},[17,659,660],{},"warn(message, **data)",[17,662,663],{},"warning(...)",[637,665,666],{},"WARN",[622,668,669,674],{},[637,670,671],{},[17,672,673],{},"error(message, **data)",[637,675,676],{},"ERROR",[622,678,679,684],{},[637,680,681],{},[17,682,683],{},"exception(message, **data)",[637,685,686],{},"ERROR, with the exception being handled",[622,688,689,697],{},[637,690,691,159,694],{},[17,692,693],{},"fatal(message, **data)",[17,695,696],{},"critical(...)",[637,698,699],{},"FATAL",[622,701,702,707],{},[637,703,704],{},[17,705,706],{},"flush(timeout=None)",[637,708,709,710,713,714,717],{},"Waits for queued logs to send; ",[17,711,712],{},"False"," if ",[17,715,716],{},"timeout"," seconds ran out first",[14,719,720,721,723,724,727],{},"The module's functions log with the client ",[17,722,239],{}," made. ",[17,725,726],{},"LumberClient"," has the same methods, for when you need more than one.",[32,729,731],{"id":730},"data","Data",[14,733,734],{},"Keyword arguments become the log's fields:",[37,736,738],{"className":86,"code":737,"language":12,"meta":42,"style":42},"lumber.info(\n    \"User signed in\",\n    request_id=\"req-abc\",           # the log's request ID\n    trace_id=\"trace-xyz\",           # the log's trace ID\n    context={\"region\": \"us-east\"},  # merged into its context\n    metadata={\"plan\": \"pro\"},       # merged into its metadata\n    user_id=123,                    # any other keyword goes into metadata\n    exc_info=err,                   # an exception (or True for the one being handled)\n)\n",[17,739,740,745,752,768,783,806,829,845,858],{"__ignoreMap":42},[46,741,742],{"class":48,"line":49},[46,743,744],{"class":98},"lumber.info(\n",[46,746,747,750],{"class":48,"line":102},[46,748,749],{"class":56},"    \"User signed in\"",[46,751,507],{"class":98},[46,753,754,757,759,762,765],{"class":48,"line":116},[46,755,756],{"class":129},"    request_id",[46,758,133],{"class":94},[46,760,761],{"class":56},"\"req-abc\"",[46,763,764],{"class":98},",           ",[46,766,767],{"class":327},"# the log's request ID\n",[46,769,770,773,775,778,780],{"class":48,"line":123},[46,771,772],{"class":129},"    trace_id",[46,774,133],{"class":94},[46,776,777],{"class":56},"\"trace-xyz\"",[46,779,764],{"class":98},[46,781,782],{"class":327},"# the log's trace ID\n",[46,784,785,788,790,792,795,797,800,803],{"class":48,"line":145},[46,786,787],{"class":129},"    context",[46,789,133],{"class":94},[46,791,387],{"class":98},[46,793,794],{"class":56},"\"region\"",[46,796,393],{"class":98},[46,798,799],{"class":56},"\"us-east\"",[46,801,802],{"class":98},"},  ",[46,804,805],{"class":327},"# merged into its context\n",[46,807,808,811,813,815,818,820,823,826],{"class":48,"line":150},[46,809,810],{"class":129},"    metadata",[46,812,133],{"class":94},[46,814,387],{"class":98},[46,816,817],{"class":56},"\"plan\"",[46,819,393],{"class":98},[46,821,822],{"class":56},"\"pro\"",[46,824,825],{"class":98},"},       ",[46,827,828],{"class":327},"# merged into its metadata\n",[46,830,831,834,836,839,842],{"class":48,"line":174},[46,832,833],{"class":129},"    user_id",[46,835,133],{"class":94},[46,837,838],{"class":167},"123",[46,840,841],{"class":98},",                    ",[46,843,844],{"class":327},"# any other keyword goes into metadata\n",[46,846,847,850,852,855],{"class":48,"line":205},[46,848,849],{"class":129},"    exc_info",[46,851,133],{"class":94},[46,853,854],{"class":98},"err,                   ",[46,856,857],{"class":327},"# an exception (or True for the one being handled)\n",[46,859,860],{"class":48,"line":360},[46,861,171],{"class":98},[14,863,864,865,868,869,872,873,876,877,880,881,884],{},"An explicit ",[17,866,867],{},"metadata"," key wins over a colliding keyword. An exception goes into metadata as ",[17,870,871],{},"exception"," (",[17,874,875],{},"ValueError: bad amount",") and ",[17,878,879],{},"traceback",". Values JSON can't hold are sent as text (a ",[17,882,883],{},"datetime"," as ISO 8601, a set as a list), and a NaN as null. Everything, the message included, is encrypted.",[32,886,888],{"id":887},"options","Options",[37,890,892],{"className":86,"code":891,"language":12,"meta":42,"style":42},"lumber.config(\n    api_key=os.environ[\"LUMBER_API_KEY\"],\n    environment=\"production\",  # sent as `env` in every log's context\n    auto_context=True,         # send the process id and hostname with every log\n    caller=False,              # also send the file, line and function that logged\n    caller_depth=0,            # frames to skip for `caller`, one per wrapper around Lumber\n    timeout=10.0,              # seconds to wait for Lumber to answer one log\n    max_queue=10_000,          # logs waiting to send before new ones are dropped\n    shutdown_timeout=5.0,      # seconds queued logs get when the program exits\n)\n",[17,893,894,899,912,928,944,959,975,990,1006,1022],{"__ignoreMap":42},[46,895,896],{"class":48,"line":49},[46,897,898],{"class":98},"lumber.config(\n",[46,900,901,904,906,908,910],{"class":48,"line":102},[46,902,903],{"class":129},"    api_key",[46,905,133],{"class":94},[46,907,136],{"class":98},[46,909,139],{"class":56},[46,911,547],{"class":98},[46,913,914,917,919,922,925],{"class":48,"line":116},[46,915,916],{"class":129},"    environment",[46,918,133],{"class":94},[46,920,921],{"class":56},"\"production\"",[46,923,924],{"class":98},",  ",[46,926,927],{"class":327},"# sent as `env` in every log's context\n",[46,929,930,933,935,938,941],{"class":48,"line":123},[46,931,932],{"class":129},"    auto_context",[46,934,133],{"class":94},[46,936,937],{"class":167},"True",[46,939,940],{"class":98},",         ",[46,942,943],{"class":327},"# send the process id and hostname with every log\n",[46,945,946,949,951,953,956],{"class":48,"line":145},[46,947,948],{"class":129},"    caller",[46,950,133],{"class":94},[46,952,712],{"class":167},[46,954,955],{"class":98},",              ",[46,957,958],{"class":327},"# also send the file, line and function that logged\n",[46,960,961,964,966,969,972],{"class":48,"line":150},[46,962,963],{"class":129},"    caller_depth",[46,965,133],{"class":94},[46,967,968],{"class":167},"0",[46,970,971],{"class":98},",            ",[46,973,974],{"class":327},"# frames to skip for `caller`, one per wrapper around Lumber\n",[46,976,977,980,982,985,987],{"class":48,"line":174},[46,978,979],{"class":129},"    timeout",[46,981,133],{"class":94},[46,983,984],{"class":167},"10.0",[46,986,955],{"class":98},[46,988,989],{"class":327},"# seconds to wait for Lumber to answer one log\n",[46,991,992,995,997,1000,1003],{"class":48,"line":205},[46,993,994],{"class":129},"    max_queue",[46,996,133],{"class":94},[46,998,999],{"class":167},"10_000",[46,1001,1002],{"class":98},",          ",[46,1004,1005],{"class":327},"# logs waiting to send before new ones are dropped\n",[46,1007,1008,1011,1013,1016,1019],{"class":48,"line":360},[46,1009,1010],{"class":129},"    shutdown_timeout",[46,1012,133],{"class":94},[46,1014,1015],{"class":167},"5.0",[46,1017,1018],{"class":98},",      ",[46,1020,1021],{"class":327},"# seconds queued logs get when the program exits\n",[46,1023,1024],{"class":48,"line":411},[46,1025,171],{"class":98},[32,1027,1029],{"id":1028},"delivery","Delivery",[14,1031,1032,1033,1039],{},"Logs are sent in order, one ",[22,1034,1036],{"href":1035},"\u002Fdocs\u002Fhttp-api",[17,1037,1038],{},"POST \u002Flogs"," per log, from a daemon thread over a connection kept open between logs.",[1041,1042,1043,1047,1050,1053],"ul",{},[1044,1045,1046],"li",{},"A network error or a 5xx counts as a failed attempt. Each log gets 5 attempts, waiting 1, 2, 4, then 8 seconds between them, and is then dropped with a warning on stderr.",[1044,1048,1049],{},"A log Lumber refuses (a 4xx, such as an invalid API key) is dropped at once with a warning, since sending it again won't help.",[1044,1051,1052],{},"When your team has sent its plan's logs for the month, Lumber answers 429: the client warns once and drops logs until the month turns.",[1044,1054,1055,1056,1059],{},"While Lumber can't be reached, up to ",[17,1057,1058],{},"max_queue"," logs wait; past that, new ones are dropped.",[14,1061,1062],{},"Forking servers (gunicorn, uWSGI) are handled: a worker process starts its own sending thread and connection with its first log.",[32,1064,1066],{"id":1065},"source","Source",[14,1068,1069,1070,1075,1076,1080],{},"The client is open source: ",[22,1071,1074],{"href":1072,"rel":1073},"https:\u002F\u002Fgithub.com\u002Finfinitetoken\u002FLumber-Python",[68],"Lumber-Python"," on GitHub, published as ",[22,1077,19],{"href":1078,"rel":1079},"https:\u002F\u002Fpypi.org\u002Fproject\u002Flumber-cloud\u002F",[68]," on PyPI. It's tested against the same known answers for encryption and the wire format as Lumber's other clients.",[1082,1083,1084],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":42,"searchDepth":102,"depth":102,"links":1086},[1087,1088,1089,1093,1094,1095,1096,1097],{"id":34,"depth":102,"text":35},{"id":82,"depth":102,"text":83},{"id":259,"depth":102,"text":1090,"children":1091},"With logging",[1092],{"id":471,"depth":116,"text":472},{"id":613,"depth":102,"text":614},{"id":730,"depth":102,"text":731},{"id":887,"depth":102,"text":888},{"id":1028,"depth":102,"text":1029},{"id":1065,"depth":102,"text":1066},"Encrypted logging for Python with lumber-cloud: install it, send logs from Python's logging module or Django, and every option.","md",{},"\u002Fdocs\u002Fpython",{"title":5,"description":1098},"docs\u002F03.python","GE5WD8zUguO9H5XyyElah0iVuFIG49qAHyFp5Vod81E",[1106,1110],{"title":1107,"path":1108,"stem":1109,"children":-1},"Node.js","\u002Fdocs\u002Fnode","docs\u002F02.node",{"title":1111,"path":1112,"stem":1113,"children":-1},"Go","\u002Fdocs\u002Fgo","docs\u002F04.go",1794332090911]