Coverage for tests/test_logFormatter.py: 21%
104 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-21 01:20 -0800
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-21 01:20 -0800
1# This file is part of daf_butler.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28"""Tests for ButlerLogRecordsFormatter."""
30import json
31import logging
32import os
33import sys
34import tempfile
35import unittest
36from logging import FileHandler
38from lsst.daf.butler import Butler, DatasetRef, DatasetType, FileDataset
39from lsst.daf.butler.logging import (
40 ButlerLogRecordHandler,
41 ButlerLogRecords,
42 JsonLogFormatter,
43 _ButlerLogRecordsModelV1,
44)
45from lsst.daf.butler.tests.utils import makeTestTempDir, removeTestTempDir
47TESTDIR = os.path.abspath(os.path.dirname(__file__))
50class ButlerLogRecordsFormatterTestCase(unittest.TestCase):
51 """Test for ButlerLogRecords put/get."""
53 def setUp(self):
54 self.root = makeTestTempDir(TESTDIR)
55 Butler.makeRepo(self.root)
57 self.run = "testrun"
58 self.butler = Butler.from_config(self.root, run=self.run)
59 self.enterContext(self.butler)
60 self.datasetType = DatasetType("test_logs", [], "ButlerLogRecords", universe=self.butler.dimensions)
62 self.butler.registry.registerDatasetType(self.datasetType)
64 def tearDown(self):
65 removeTestTempDir(self.root)
67 def testButlerLogRecordsFormatter(self):
68 """Test that we can get and put records handled by
69 ButlerLogRecordHandler.
70 """
71 handler = ButlerLogRecordHandler()
73 log = logging.getLogger(self.id())
74 log.setLevel(logging.INFO)
75 log.addHandler(handler)
77 log.info("An INFO message")
78 log.debug("A DEBUG message")
79 log.warning("A WARNING message")
81 ref = self.butler.put(handler.records, self.datasetType)
82 records = self.butler.get(ref)
84 self.assertEqual(records, handler.records)
85 self.assertEqual(len(records), 2)
87 def testButlerLogRecordsFormatterExtra(self):
88 """Test that we can get and put records handled by
89 ButlerLogRecordHandler with extra JSON data attached.
90 """
91 handler = ButlerLogRecordHandler()
93 log = logging.getLogger(self.id())
94 log.setLevel(logging.INFO)
95 log.addHandler(handler)
97 log.info("An INFO message")
98 log.debug("A DEBUG message")
99 log.warning("A WARNING message")
101 extra_data = {"extra1": 1, "extra2": 2}
102 handler.records.extra = extra_data
103 ref = self.butler.put(handler.records, self.datasetType)
104 records = self.butler.get(ref)
106 self.assertEqual(records, handler.records)
107 self.assertEqual(len(records), 2)
109 @unittest.skipIf(
110 sys.version_info < (3, 12, 0),
111 "This test requires NamedTemporaryFile behavior not available in older Python versions.",
112 )
113 def testButlerLogRecordsFormatterV1(self):
114 """Test that we can read log records stored via the old V1 format
115 (just a JSON list).
116 """
117 handler = ButlerLogRecordHandler()
119 log = logging.getLogger(self.id())
120 log.setLevel(logging.INFO)
121 log.addHandler(handler)
123 log.info("An INFO message")
124 log.debug("A DEBUG message")
125 log.warning("A WARNING message")
127 with tempfile.NamedTemporaryFile(
128 mode="w", suffix=".json", prefix="butler-log-", delete_on_close=False
129 ) as tmp:
130 # We can't use butler.put since that always writes the new format,
131 # so we write manually and ingest.
132 tmp.write(
133 _ButlerLogRecordsModelV1(root=handler.records._records).model_dump_json(
134 exclude_unset=True, exclude_defaults=True
135 )
136 )
137 tmp.close()
138 ref = DatasetRef(self.datasetType, dataId={}, run=self.run)
139 dataset = FileDataset(path=os.path.abspath(tmp.name), refs=ref)
140 self.butler.ingest(dataset, transfer="move")
142 records = self.butler.get(ref)
143 self.assertEqual(records, handler.records)
144 self.assertEqual(len(records), 2)
146 @unittest.skipIf(
147 sys.version_info < (3, 12, 0),
148 "This test requires NamedTemporaryFile behavior not available in older Python versions.",
149 )
150 def testJsonLogRecordsFormatter(self):
151 """Test that externally created JSON format stream files work."""
152 log = logging.getLogger(self.id())
153 log.setLevel(logging.INFO)
155 with tempfile.NamedTemporaryFile(mode="w", suffix=".json", prefix="butler-log-") as tmp:
156 handler = FileHandler(tmp.name)
157 handler.setFormatter(JsonLogFormatter())
158 log.addHandler(handler)
160 log.info("An INFO message")
161 log.debug("A DEBUG message")
162 log.warning("A WARNING message")
164 handler.close()
166 # Now ingest the file.
167 ref = DatasetRef(self.datasetType, dataId={}, run=self.run)
168 dataset = FileDataset(path=tmp.name, refs=ref)
169 self.butler.ingest(dataset, transfer="move")
171 records = self.butler.get(ref)
172 self.assertEqual(len(records), 2)
174 @unittest.skipIf(
175 sys.version_info < (3, 12, 0),
176 "This test requires NamedTemporaryFile behavior not available in older Python versions.",
177 )
178 def testJsonLogRecordsFormatterExtra(self):
179 """Test that externally created JSON format stream files work with
180 extra JSON data appended.
181 """
182 log = logging.getLogger(self.id())
183 log.setLevel(logging.INFO)
185 with tempfile.NamedTemporaryFile(mode="w", suffix=".json", prefix="butler-log-") as tmp:
186 handler = FileHandler(tmp.name)
187 handler.setFormatter(JsonLogFormatter())
188 log.addHandler(handler)
190 log.info("An INFO message")
191 log.debug("A DEBUG message")
192 log.warning("A WARNING message")
194 handler.close()
195 extra_data = {"extra1": 1, "extra2": 2}
196 with open(tmp.name, "a") as stream:
197 ButlerLogRecords.write_streaming_extra(stream, json.dumps(extra_data))
199 # Now ingest the file.
200 ref = DatasetRef(self.datasetType, dataId={}, run=self.run)
201 dataset = FileDataset(path=tmp.name, refs=ref)
202 self.butler.ingest(dataset, transfer="move")
204 records: ButlerLogRecords = self.butler.get(ref)
205 self.assertEqual(len(records), 2)
206 self.assertEqual(records.extra, extra_data)
209if __name__ == "__main__":
210 unittest.main()