diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn
index 430f209a7998c0d1d4026e9095ca654c2d654a50..42780e9b2317c055c5ea58da14e56061b3153b21 100644
--- a/.clj-kondo/config.edn
+++ b/.clj-kondo/config.edn
@@ -24,22 +24,22 @@
     (taoensso.nippy/extend-freeze)
     (taoensso.nippy/extend-thaw)]}
 
-  :refer-all                    {:level   :warning
-                                 :exclude [clojure.test]}
+  :refer-all                                {:level   :warning
+                                             :exclude [clojure.test]}
   ;; TODO (cam): I think we just need to tell it how to handle MBQL match and we can enable this?
-  :unexpected-recur             {:level :off}
+  :unexpected-recur                         {:level :off}
   ;; TODO (cam): can we fix these?
-  :unused-referred-var          {:exclude {compojure.core [GET DELETE POST PUT]}}
-  :missing-else-branch          {:level :warning}
-  :misplaced-docstring          {:level :warning}
-  :non-arg-vec-return-type-hint {:level :warning}
-  :missing-body-in-when         {:level :warning}
-  :missing-docstring            {:level :warning}
+  :unused-referred-var                      {:exclude {compojure.core [GET DELETE POST PUT]}}
+  :missing-else-branch                      {:level :warning}
+  :misplaced-docstring                      {:level :warning}
+  :non-arg-vec-return-type-hint             {:level :warning}
+  :missing-body-in-when                     {:level :warning}
+  :missing-docstring                        {:level :warning}
   ;; TODO (braden): This is useful, but it doesn't grok eg. enterprise/backend/src
-  :namespace-name-mismatch      {:level :off}
-  :use                          {:level :warning}
-  :redundant-fn-wrapper         {:level :warning}
-  :invalid-arity                {:skip-args [metabase.mbql.util.match/match]}
+  :namespace-name-mismatch                  {:level :off}
+  :use                                      {:level :warning}
+  :redundant-fn-wrapper                     {:level :warning}
+  :invalid-arity                            {:skip-args [metabase.mbql.util.match/match]}
   ;; TODO (cam): here are some more linters we should experiment with enabling -- some might be useful.
   ;; :docstring-no-summary                  {:level :warning}
   ;; :docstring-leading-trailing-whitespace {:level :warning}
@@ -83,7 +83,12 @@
     schema.core/either                                                           {:namespaces ["metabase.*"]}}}
 
   :discouraged-var
-  {clojure.string/lower-case {:message "Use metabase.util/lower-case-en instead of clojure.string/lower-case"}
+  {clojure.core/print        {:message "Use clojure.tools.logging instead of clojure.core/print"}
+   clojure.core/println      {:message "Use clojure.tools.logging instead of clojure.core/println"}
+   clojure.core/printf       {:message "Use clojure.tools.logging instead of clojure.core/printf"}
+   clojure.core/prn          {:message "Use clojure.tools.logging instead of clojure.core/prn"}
+   clojure.core/pr           {:message "Use clojure.tools.logging instead of clojure.core/pr"}
+   clojure.string/lower-case {:message "Use metabase.util/lower-case-en instead of clojure.string/lower-case"}
    clojure.string/upper-case {:message "Use metabase.util/upper-case-en instead of clojure.string/upper-case"}
    honeysql.core/call        {:message "Use hx/call instead because it is Honey SQL 2 friendly"}
    honeysql.core/raw         {:message "Use hx/raw instead because it is Honey SQL 2 friendly"}
@@ -94,12 +99,13 @@
   {:exclude
    [colorize.core]}
 
-  :unsorted-required-namespaces {:level :warning}
+  :unsorted-required-namespaces             {:level :warning}
 
   :consistent-alias
   {:aliases
    {buddy.core.hash                                                 buddy-hash
     cheshire.generate                                               json.generate
+    clojure.tools.logging                                           log
     clj-http.client                                                 http
     clj-ldap.client                                                 ldap
     clj-time.coerce                                                 time.coerce
@@ -659,14 +665,19 @@
  ;; this list isn't exhaustive because it misses some stuff like the test runner and HTTP client but it's easier to go
  ;; fix those namespaces than it is to make this regex super hairy.
  [{:pattern "(?:.*-test(?:\\..*)?$)|(?:.*test-util$)|(?:^metabase\\.test.*)"
-   :name    test-namespaces}]
+   :name    test-namespaces}
+  {:pattern "metabase\\.cmd.*"
+   :name    printable-namespaces}]
 
  :config-in-ns
  {test-namespaces
   {:linters
-   {:inline-def        {:level :off}
-    :missing-docstring {:level :off}
-    :private-call      {:level :off}
+   {:inline-def                                    {:level :off}
+    :missing-docstring                             {:level :off}
+    :private-call                                  {:level :off}
 
     ;; custom linters
-    :hooks.metabase.test.data/mbql-query-first-arg {:level :error}}}}}
+    :hooks.metabase.test.data/mbql-query-first-arg {:level :error}}}
+  printable-namespaces
+  {:linters
+   {:discouraged-var {:level :off}}}}}
diff --git a/.clj-kondo/hooks/common.clj b/.clj-kondo/hooks/common.clj
index d73a17a26ccef8272140c6facaa3c7139d8c1fa8..5472541e0293910ba0fbc4771a1b3e4479aa5363 100644
--- a/.clj-kondo/hooks/common.clj
+++ b/.clj-kondo/hooks/common.clj
@@ -44,11 +44,12 @@
   "This is the same idea as [[clojure.core/do]] but doesn't cause Kondo to complain about redundant dos."
   ;; This used to use `do` as the token-node, but as of version 2022.10.14 that resulted in warnings about
   ;; unused variables since Kondo was smart enough to realize that we sometimes were calling pure functions early in
-  ;; the `do` and the value was getting thrown away. `print` tricks Kondo into thinking everything is used.
+  ;; the `do` and the value was getting thrown away. `noop` tricks Kondo into thinking everything is used.
   [{{[_ & args] :children} :node}]
-  (let [node* (hooks/list-node
+  (let [noop (constantly nil)
+        node* (hooks/list-node
                (list*
-                (hooks/token-node 'print)
+                (hooks/token-node noop)
                 args))]
     {:node node*}))
 
diff --git a/.clj-kondo/hooks/metabase/test/data.clj b/.clj-kondo/hooks/metabase/test/data.clj
index 5ea70d2b26cb43284ccb14b420b30935c170dd1f..bf4249cece79874a490aeecddc169489c384fc78 100644
--- a/.clj-kondo/hooks/metabase/test/data.clj
+++ b/.clj-kondo/hooks/metabase/test/data.clj
@@ -43,7 +43,8 @@
 
 (defn dataset
   [{{[_ dataset & body] :children} :node}]
-  (let [body (case (dataset-type dataset)
+  (let [noop (constantly nil)
+        body (case (dataset-type dataset)
                ;; non-symbol, qualified symbols, and unqualified symbols from the current namespace/let-bound can all
                ;; get converted from something like
                ;;
@@ -67,7 +68,7 @@
                ;; (this used to be a `do` form (which makes a lot more semantic sense), but that resulted in warnings
                ;; about unused values
                (:unqualified/from-dataset-defs-namespace :unqualified/unknown)
-               (list* (hooks/token-node 'print)
+               (list* (hooks/token-node noop)
                       body))]
     {:node (with-meta (hooks/list-node (with-meta body
                                                   (meta dataset)))
diff --git a/.clj-kondo/macros/metabase/test/util.clj b/.clj-kondo/macros/metabase/test/util.clj
index d03ee9b976dd90834fd5f2f49584d9bb50d3298c..bbd2e29fc58612bee8bc8fda992f534a2dff61af 100644
--- a/.clj-kondo/macros/metabase/test/util.clj
+++ b/.clj-kondo/macros/metabase/test/util.clj
@@ -1,11 +1,11 @@
 (ns macros.metabase.test.util)
 
 (defmacro with-temp-env-var-value [bindings & body]
-  `(print
+  `((constantly nil)
     ~@(map second (partition-all 2 bindings))
     ~@body))
 
 (defmacro with-temporary-raw-setting-values [bindings & body]
-  `(print
+  `((constantly nil)
      ~@(map second (partition-all 2 bindings))
      ~@body))
diff --git a/enterprise/backend/src/metabase_enterprise/sandbox/models/group_table_access_policy.clj b/enterprise/backend/src/metabase_enterprise/sandbox/models/group_table_access_policy.clj
index c2748fee64d28b1c1e1211e34695d3cea60e2f7f..98cc7775b2c8e4a4e5a6c7b0a4e9a340c15cc73c 100644
--- a/enterprise/backend/src/metabase_enterprise/sandbox/models/group_table_access_policy.clj
+++ b/enterprise/backend/src/metabase_enterprise/sandbox/models/group_table_access_policy.clj
@@ -34,10 +34,10 @@
 (when *compile-files*
   (defonce previous-compilation-trace (atom nil))
   (when @previous-compilation-trace
-    (println "THIS FILE HAS ALREADY BEEN COMPILED!!!!!")
-    (println "This compilation trace:")
+    (log/info "THIS FILE HAS ALREADY BEEN COMPILED!!!!!")
+    (log/info "This compilation trace:")
     ((requiring-resolve 'clojure.pprint/pprint) (vec (.getStackTrace (Thread/currentThread))))
-    (println "Previous compilation trace:")
+    (log/info "Previous compilation trace:")
     ((requiring-resolve 'clojure.pprint/pprint) @previous-compilation-trace)
     (throw (ex-info "THIS FILE HAS ALREADY BEEN COMPILED!!!!!" {})))
   (reset! previous-compilation-trace (vec (.getStackTrace (Thread/currentThread)))))
diff --git a/enterprise/backend/src/metabase_enterprise/serialization/v2/extract.clj b/enterprise/backend/src/metabase_enterprise/serialization/v2/extract.clj
index bd98ad59b853147fba7cbf63e481fd1fd82976e9..c7dbc7d9114ad7badb2796f48cc909dc85e42c70 100644
--- a/enterprise/backend/src/metabase_enterprise/serialization/v2/extract.clj
+++ b/enterprise/backend/src/metabase_enterprise/serialization/v2/extract.clj
@@ -132,25 +132,25 @@
   "Given the analysis map from [[escape-analysis]], report the results in a human-readable format with Card titles etc."
   [{:keys [escaped-dashcards escaped-questions]}]
   (when-not (empty? escaped-dashcards)
-    (println "Dashboard cards outside the collection")
-    (println "======================================")
+    (log/info "Dashboard cards outside the collection")
+    (log/info "======================================")
     (doseq [[dash-id card-ids] escaped-dashcards
             :let [dash-name (db/select-one-field :name Dashboard :id dash-id)]]
-      (printf "Dashboard %d: %s\n" dash-id dash-name)
+      (log/infof "Dashboard %d: %s\n" dash-id dash-name)
       (doseq [card_id card-ids
               :let [card (db/select-one [Card :collection_id :name] :id card_id)]]
-        (printf "          \tCard %d: %s\n"    card_id (:name card))
-        (printf "        from collection %s\n" (collection-label (:collection_id card))))))
+        (log/infof "          \tCard %d: %s\n"    card_id (:name card))
+        (log/infof "        from collection %s\n" (collection-label (:collection_id card))))))
 
   (when-not (empty? escaped-questions)
-    (println "Questions based on outside questions")
-    (println "====================================")
+    (log/info "Questions based on outside questions")
+    (log/info "====================================")
     (doseq [[curated-id alien-id] escaped-questions
             :let [curated-card (db/select-one [Card :collection_id :name] :id curated-id)
                   alien-card   (db/select-one [Card :collection_id :name] :id alien-id)]]
-      (printf "%-4d      %s    (%s)\n  -> %-4d %s    (%s)\n"
-              curated-id (:name curated-card) (collection-label (:collection_id curated-card))
-              alien-id   (:name alien-card)   (collection-label (:collection_id alien-card))))))
+      (log/infof "%-4d      %s    (%s)\n  -> %-4d %s    (%s)\n"
+                 curated-id (:name curated-card) (collection-label (:collection_id curated-card))
+                 alien-id   (:name alien-card)   (collection-label (:collection_id alien-card))))))
 
 (defn extract-subtrees
   "Extracts the targeted entities and all their descendants into a reducible stream of extracted maps.
diff --git a/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj b/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj
index b3bc5bb1f66e8ccdb698c929542ec169cfce35b9..b8f52bfe1cc09a0579a0532fb51eee32df634ce8 100644
--- a/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj
+++ b/enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/row_level_restrictions_test.clj
@@ -3,6 +3,7 @@
    [clojure.core.async :as a]
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [honeysql.core :as hsql]
    [medley.core :as m]
    [metabase-enterprise.sandbox.models.group-table-access-policy
@@ -426,7 +427,7 @@
                                            (reset! remark <>)))]
       (let [results (run-query-fn)]
         (or (some-> @remark (str/replace #"queryHash: \w+" "queryHash: <hash>"))
-            (println "NO REMARK FOUND:\n" (u/pprint-to-str 'red results))
+            (log/infof "NO REMARK FOUND:\n %s" (u/pprint-to-str 'red results))
             (throw (ex-info "No remark found!" {:results results})))))))
 
 (deftest remark-test
diff --git a/modules/drivers/bigquery-cloud-sdk/test/metabase/test/data/bigquery_cloud_sdk.clj b/modules/drivers/bigquery-cloud-sdk/test/metabase/test/data/bigquery_cloud_sdk.clj
index 1fc6af52e4746fb1cad69faa1d273f133f7f52ac..fdc941086163ad15f8c34cc6d689ccf4d8aac91b 100644
--- a/modules/drivers/bigquery-cloud-sdk/test/metabase/test/data/bigquery_cloud_sdk.clj
+++ b/modules/drivers/bigquery-cloud-sdk/test/metabase/test/data/bigquery_cloud_sdk.clj
@@ -1,5 +1,6 @@
 (ns metabase.test.data.bigquery-cloud-sdk
   (:require [clojure.string :as str]
+            [clojure.tools.logging :as log]
             [flatland.ordered.map :as ordered-map]
             [java-time :as t]
             [medley.core :as m]
@@ -92,14 +93,14 @@
 (defn- create-dataset! [^String dataset-id]
   {:pre [(seq dataset-id)]}
   (.create (bigquery) (DatasetInfo/of (DatasetId/of (project-id) dataset-id)) (u/varargs BigQuery$DatasetOption))
-  (println (u/format-color 'blue "Created BigQuery dataset `%s.%s`." (project-id) dataset-id)))
+  (log/info (u/format-color 'blue "Created BigQuery dataset `%s.%s`." (project-id) dataset-id)))
 
 (defn- destroy-dataset! [^String dataset-id]
   {:pre [(seq dataset-id)]}
   (.delete (bigquery) dataset-id (u/varargs
                                    BigQuery$DatasetDeleteOption
                                    [(BigQuery$DatasetDeleteOption/deleteContents)]))
-  (println (u/format-color 'red "Deleted BigQuery dataset `%s.%s`." (project-id) dataset-id)))
+  (log/error (u/format-color 'red "Deleted BigQuery dataset `%s.%s`." (project-id) dataset-id)))
 
 (defn execute!
   "Execute arbitrary (presumably DDL) SQL statements against the test project. Waits for statement to complete, throwing
@@ -107,7 +108,7 @@
   ^TableResult [format-string & args]
   (driver/with-driver :bigquery-cloud-sdk
     (let [sql (apply format format-string args)]
-      (printf "[BigQuery] %s\n" sql)
+      (log/infof "[BigQuery] %s\n" sql)
       (flush)
       (#'bigquery/execute-bigquery-on-db (data/db) sql nil nil nil))))
 
@@ -121,7 +122,7 @@
 (s/defn ^:private delete-table!
   [dataset-id :- su/NonBlankString, table-id :- su/NonBlankString]
   (.delete (bigquery) (TableId/of dataset-id table-id))
-  (println (u/format-color 'red "Deleted table `%s.%s.%s`" (project-id) dataset-id table-id)))
+  (log/error (u/format-color 'red "Deleted table `%s.%s.%s`" (project-id) dataset-id table-id)))
 
 (s/defn ^:private create-table!
   [^String dataset-id :- su/NonBlankString
@@ -139,7 +140,7 @@
     (.create (bigquery) tbl (u/varargs BigQuery$TableOption)))
   ;; now verify that the Table was created
   (.listTables (bigquery) dataset-id (u/varargs BigQuery$TableListOption))
-  (println (u/format-color 'blue "Created BigQuery table `%s.%s.%s`." (project-id) dataset-id table-id)))
+  (log/info (u/format-color 'blue "Created BigQuery table `%s.%s.%s`." (project-id) dataset-id table-id)))
 
 (defn- table-row-count ^Integer [^String dataset-id, ^String table-id]
   (let [sql                           (format "SELECT count(*) FROM `%s.%s.%s`" (project-id) dataset-id table-id)
@@ -204,17 +205,16 @@
 (defn- insert-data! [^String dataset-id ^String table-id row-maps]
   {:pre [(seq dataset-id) (seq table-id) (sequential? row-maps) (seq row-maps) (every? map? row-maps)]}
   (doseq [chunk (partition-all max-rows-per-request row-maps)
-          :let  [_                           (println (format
-                                                        "Inserting %d rows like\n%s"
+          :let  [_                           (log/infof "Inserting %d rows like\n%s"
                                                         (count chunk)
-                                                        (u/pprint-to-str (first chunk))))
+                                                        (u/pprint-to-str (first chunk)))
                  req                         (rows->request dataset-id table-id chunk)
                  ^InsertAllResponse response (.insertAll (bigquery) req)]]
-    (println (u/format-color 'blue "Sent request to insert %d rows into `%s.%s.%s`"
-               (count (.getRows req))
-               (project-id) dataset-id table-id))
+    (log/info  (u/format-color 'blue "Sent request to insert %d rows into `%s.%s.%s`"
+                (count (.getRows req))
+                (project-id) dataset-id table-id))
     (when (seq (.getInsertErrors response))
-      (println "Error inserting rows:" (u/pprint-to-str (seq (.getInsertErrors response))))
+      (log/errorf "Error inserting rows: %s" (u/pprint-to-str (seq (.getInsertErrors response))))
       (throw (ex-info "Error inserting rows"
                       {:errors                       (seq (.getInsertErrors response))
                        :metabase.util/no-auto-retry? true
@@ -223,25 +223,24 @@
   ;; Wait up to 120 seconds for all the rows to be loaded and become available by BigQuery
   (let [max-wait-seconds   120
         expected-row-count (count row-maps)]
-    (println (format "Waiting for %d rows to be loaded..." expected-row-count))
+    (log/infof "Waiting for %d rows to be loaded..." expected-row-count)
     (loop [seconds-to-wait-for-load max-wait-seconds]
       (let [actual-row-count (table-row-count dataset-id table-id)]
         (cond
           (= expected-row-count actual-row-count)
           (do
-            (println (format "Loaded %d rows in %d seconds." expected-row-count (- max-wait-seconds seconds-to-wait-for-load)))
+            (log/infof "Loaded %d rows in %d seconds." expected-row-count (- max-wait-seconds seconds-to-wait-for-load))
             :ok)
 
           (> seconds-to-wait-for-load 0)
           (do (Thread/sleep 1000)
-              (print ".")
-              (flush)
+              (log/info ".")
               (recur (dec seconds-to-wait-for-load)))
 
           :else
           (let [error-message (format "Failed to load table data for `%s.%s.%s`: expected %d rows, loaded %d"
                                       (project-id) dataset-id table-id expected-row-count actual-row-count)]
-            (println (u/format-color 'red error-message))
+            (log/error (u/format-color 'red error-message))
             (throw (ex-info error-message {:metabase.util/no-auto-retry? true}))))))))
 
 (defn base-type->bigquery-type [base-type]
@@ -269,7 +268,7 @@
     (for [{:keys [field-name base-type]} field-definitions]
       [field-name (or (base-type->bigquery-type base-type)
                       (let [message (format "Don't know what BigQuery type to use for base type: %s" base-type)]
-                        (println (u/format-color 'red message))
+                        (log/error (u/format-color 'red message))
                         (throw (ex-info message {:metabase.util/no-auto-retry? true}))))]))))
 
 (defn- tabledef->prepared-rows
@@ -327,12 +326,12 @@
     (let [{transient-datasets true non-transient-datasets false} (group-by transient-dataset?
                                                                    (existing-dataset-names))]
       (reset! existing-datasets (set non-transient-datasets))
-      (println "These BigQuery datasets have already been loaded:\n" (u/pprint-to-str (sort @existing-datasets)))
+      (log/infof "These BigQuery datasets have already been loaded:\n%s" (u/pprint-to-str (sort @existing-datasets)))
       (when-let [outdated-transient-datasets (seq (filter transient-dataset-outdated? transient-datasets))]
-        (println (u/format-color
-                   'blue
-                   "These BigQuery datasets are transient, and more than two hours old; deleting them: %s`."
-                   (u/pprint-to-str (sort outdated-transient-datasets))))
+        (log/info (u/format-color
+                    'blue
+                    "These BigQuery datasets are transient, and more than two hours old; deleting them: %s`."
+                    (u/pprint-to-str (sort outdated-transient-datasets))))
         (doseq [delete-ds outdated-transient-datasets]
           (u/ignore-exceptions
             (destroy-dataset! delete-ds))))))
@@ -343,7 +342,7 @@
         (destroy-dataset! database-name))
       (u/auto-retry 2
         (try
-          (println (format "Creating dataset %s..." (pr-str database-name)))
+          (log/infof "Creating dataset %s..." (pr-str database-name))
           ;; if the dataset failed to load successfully last time around, destroy whatever was loaded so we start
           ;; again from a blank slate
           (destroy-dataset! database-name)
@@ -354,10 +353,10 @@
           (doseq [tabledef table-definitions]
             (load-tabledef! database-name tabledef))
           (swap! existing-datasets conj database-name)
-          (println (u/format-color 'green "Successfully created %s." (pr-str database-name)))
+          (log/info (u/format-color 'green "Successfully created %s." (pr-str database-name)))
           (catch Throwable e
-            (println (u/format-color 'red  "Failed to load BigQuery dataset %s." (pr-str database-name)))
-            (println (u/pprint-to-str 'red (Throwable->map e)))
+            (log/error (u/format-color 'red  "Failed to load BigQuery dataset %s." (pr-str database-name)))
+            (log/error (u/pprint-to-str 'red (Throwable->map e)))
             ;; if creating the dataset ultimately fails to complete, then delete it so it will hopefully
             ;; work next time around
             (u/ignore-exceptions
diff --git a/modules/drivers/mongo/test/metabase/driver/mongo_test.clj b/modules/drivers/mongo/test/metabase/driver/mongo_test.clj
index 4ca657bf7dc675cd3be26d41f5aaa261d062ba42..0e93e10d1b2fc71c7cf3e4fe2dd594d33c1ecbe7 100644
--- a/modules/drivers/mongo/test/metabase/driver/mongo_test.clj
+++ b/modules/drivers/mongo/test/metabase/driver/mongo_test.clj
@@ -2,6 +2,7 @@
   "Tests for Mongo driver."
   (:require [cheshire.core :as json]
             [clojure.test :refer :all]
+            [clojure.tools.logging :as log]
             [medley.core :as m]
             [metabase.automagic-dashboards.core :as magic]
             [metabase.db.metadata-queries :as metadata-queries]
@@ -438,8 +439,8 @@
                   (throw (ex-info (format "Error inserting row: %s" (ex-message e))
                                   {:database database-name, :collection collection-name, :details details, :row row}
                                   e)))))
-            (println (format "Inserted %d rows into %s collection %s."
-                             (count row-maps) (pr-str database-name) (pr-str collection-name))))
+            (log/infof "Inserted %d rows into %s collection %s."
+                       (count row-maps) (pr-str database-name) (pr-str collection-name)))
           ;; now sync the Database.
           (let [db (db/insert! Database {:name database-name, :engine "mongo", :details details})]
             (sync/sync-database! db)
diff --git a/modules/drivers/oracle/test/metabase/driver/oracle_test.clj b/modules/drivers/oracle/test/metabase/driver/oracle_test.clj
index 659008e90ab8170a2f306f6af6ea837f4ffc8e2f..4b2e805ba948146b7d9d6214c31cee6d9dc7b9e5 100644
--- a/modules/drivers/oracle/test/metabase/driver/oracle_test.clj
+++ b/modules/drivers/oracle/test/metabase/driver/oracle_test.clj
@@ -4,6 +4,7 @@
    [clojure.java.jdbc :as jdbc]
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [metabase.api.common :as api]
    [metabase.driver :as driver]
    [metabase.driver.oracle :as oracle]
@@ -363,10 +364,10 @@
                                   te/*test-drivers* (constantly #{:oracle})]
                           (testing " and execute a query correctly"
                             (qp-test.order-by-test/order-by-test))))))))))))
-      (println (u/format-color 'yellow
-                               "Skipping %s because %s env var is not set"
-                               "oracle-connect-with-ssl-test"
-                               "MB_ORACLE_SSL_TEST_SSL")))))
+      (log/warn (u/format-color 'yellow
+                                "Skipping %s because %s env var is not set"
+                                "oracle-connect-with-ssl-test"
+                                "MB_ORACLE_SSL_TEST_SSL")))))
 
 (deftest text-equals-empty-string-test
   (mt/test-driver :oracle
diff --git a/modules/drivers/oracle/test/metabase/test/data/oracle.clj b/modules/drivers/oracle/test/metabase/test/data/oracle.clj
index 55c081850762c6525df062f36fb69a21a01f30a9..e4fa20b9fa677d38455698002540ffe99584048e 100644
--- a/modules/drivers/oracle/test/metabase/test/data/oracle.clj
+++ b/modules/drivers/oracle/test/metabase/test/data/oracle.clj
@@ -2,6 +2,7 @@
   (:require [clojure.java.jdbc :as jdbc]
             [clojure.set :as set]
             [clojure.string :as str]
+            [clojure.tools.logging :as log]
             [honeysql.format :as hformat]
             [medley.core :as m]
             [metabase.db :as mdb]
@@ -128,14 +129,14 @@
           (let [existing-db-id (u/the-id existing-db)
                 all-schemas    (db/select-field :schema Table :db_id existing-db-id)]
             (when-not (= all-schemas #{session-schema})
-              (println (u/format-color 'yellow
-                                       (str "[oracle] At least one table's schema for the existing '%s' Database"
+              (log/warn (u/format-color 'yellow
+                                        (str "[oracle] At least one table's schema for the existing '%s' Database"
                                             " (id %d), which include all of [%s], does not match current session-schema"
                                             " of %s; deleting this DB so it can be recreated")
-                                       database-name
-                                       existing-db-id
-                                       (str/join "," all-schemas)
-                                       session-schema))
+                                        database-name
+                                        existing-db-id
+                                        (str/join "," all-schemas)
+                                        session-schema))
               (db/delete! Database :id existing-db-id))))
         (swap! oracle-test-dbs-created-by-this-instance conj database-name)))))
 
@@ -215,9 +216,9 @@
 ;; TL;DR Oracle schema == Oracle user. Create new user for session-schema
 (defn- execute! [format-string & args]
   (let [sql (apply format format-string args)]
-    (println (u/format-color 'blue "[oracle] %s" sql))
+    (log/info (u/format-color 'blue "[oracle] %s" sql))
     (jdbc/execute! (dbspec) sql))
-  (println (u/format-color 'blue "[ok]")))
+  (log/info (u/format-color 'blue "[ok]")))
 
 (defn create-user!
   ;; default to using session-password for all users created this session
diff --git a/modules/drivers/presto-jdbc/test/metabase/test/data/presto_jdbc.clj b/modules/drivers/presto-jdbc/test/metabase/test/data/presto_jdbc.clj
index ab99a02c6dd7e6d73c50ad777ca8f9543b61311d..88609fac29c103df7c3cf5f1b85b64806c54ba72 100644
--- a/modules/drivers/presto-jdbc/test/metabase/test/data/presto_jdbc.clj
+++ b/modules/drivers/presto-jdbc/test/metabase/test/data/presto_jdbc.clj
@@ -2,6 +2,7 @@
   "Presto JDBC driver test extensions."
   (:require [clojure.string :as str]
             [clojure.test :refer :all]
+            [clojure.tools.logging :as log]
             [metabase.config :as config]
             [metabase.connection-pool :as connection-pool]
             [metabase.driver :as driver]
@@ -119,7 +120,7 @@
             (sql-jdbc.execute/set-parameters! driver stmt params)
             (let [tbl-nm        ((comp last :components) (into {} table-identifier))
                   rows-affected (.executeUpdate stmt)]
-              (println (format "[%s] Inserted %d rows into %s." driver rows-affected tbl-nm))))
+              (log/infof "[%s] Inserted %d rows into %s." driver rows-affected tbl-nm)))
           (catch Throwable e
             (throw (ex-info (format "[%s] Error executing SQL: %s" driver (ex-message e))
                      {:driver driver, :sql sql, :params params}
diff --git a/modules/drivers/presto/test/metabase/test/data/presto.clj b/modules/drivers/presto/test/metabase/test/data/presto.clj
index 74beb3398adebc9740cbe6e391320638e28804d2..62e6e721970081c1dbb1b200b037162425ed77a1 100644
--- a/modules/drivers/presto/test/metabase/test/data/presto.clj
+++ b/modules/drivers/presto/test/metabase/test/data/presto.clj
@@ -127,9 +127,9 @@
   (let [details  (tx/dbdef->connection-details driver :db dbdef)
         execute! (partial #'presto/execute-query-for-sync details)]
     (doseq [{:keys [table-name], :as tabledef} table-definitions]
-      (println (format "[Presto] destroying %s.%s" (pr-str database-name) (pr-str table-name)))
+      (log/infof "[Presto] destroying %s.%s" (pr-str database-name) (pr-str table-name))
       (execute! (sql.tx/drop-table-if-exists-sql driver dbdef tabledef))
-      (println "[Presto] [ok]"))))
+      (log/info "[Presto] [ok]"))))
 
 (defmethod ddl.i/format-name :presto
   [_ s]
diff --git a/modules/drivers/redshift/test/metabase/test/data/redshift.clj b/modules/drivers/redshift/test/metabase/test/data/redshift.clj
index 057ee3d93f6b22307b45a6ef27d020b9f70c4389..633145a96659a457d23205f92089322d3a2edeb8 100644
--- a/modules/drivers/redshift/test/metabase/test/data/redshift.clj
+++ b/modules/drivers/redshift/test/metabase/test/data/redshift.clj
@@ -1,5 +1,6 @@
 (ns metabase.test.data.redshift
   (:require [clojure.java.jdbc :as jdbc]
+            [clojure.tools.logging :as log]
             [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn]
             [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync]
             [metabase.test.data.interface :as tx]
@@ -76,9 +77,9 @@
 (defn execute! [format-string & args]
   (let [sql  (apply format format-string args)
         spec (sql-jdbc.conn/connection-details->spec :redshift @db-connection-details)]
-    (println (u/format-color 'blue "[redshift] %s" sql))
+    (log/info (u/format-color 'blue "[redshift] %s" sql))
     (jdbc/execute! spec sql))
-  (println (u/format-color 'blue "[ok]")))
+  (log/info (u/format-color 'blue "[ok]")))
 
 (defmethod tx/before-run :redshift
   [_]
diff --git a/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj b/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj
index 2cc0c70c66ef36a84b5179c2ba0ba9e9ef188b86..ce3167e4f3396975c53deae424b22eb07a5289d3 100644
--- a/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj
+++ b/modules/drivers/snowflake/test/metabase/test/data/snowflake.clj
@@ -1,6 +1,7 @@
 (ns metabase.test.data.snowflake
   (:require [clojure.java.jdbc :as jdbc]
             [clojure.string :as str]
+            [clojure.tools.logging :as log]
             [metabase.driver.sql-jdbc.connection :as sql-jdbc.conn]
             [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync]
             [metabase.driver.sql.util.unprepare :as unprepare]
@@ -80,7 +81,7 @@
   (defn- existing-datasets []
     (when-not (seq @datasets)
       (reset! datasets (existing-dataset-names))
-      (println "These Snowflake datasets have already been loaded:\n" (u/pprint-to-str (sort @datasets))))
+      (log/infof "These Snowflake datasets have already been loaded:\n%s" (u/pprint-to-str (sort @datasets))))
     @datasets)
 
   (defn- add-existing-dataset! [database-name]
@@ -94,7 +95,7 @@
   (let [{:keys [database-name], :as db-def} (update db-def :database-name qualified-db-name)]
     ;; ok, now check if already created. If already created, no-op
     (when-not (contains? (existing-datasets) database-name)
-      (println (format "Creating new Snowflake database %s..." (pr-str database-name)))
+      (log/infof "Creating new Snowflake database %s..." (pr-str database-name))
       ;; if not created, create the DB...
       (try
         ;; call the default impl for SQL JDBC drivers
@@ -105,8 +106,8 @@
         ;; load it next time around
         (catch Throwable e
           (let [drop-db-sql (format "DROP DATABASE \"%s\";" database-name)]
-            (println "Creating DB failed:" e)
-            (println "[Snowflake]" drop-db-sql)
+            (log/errorf "Creating DB failed: %s" e)
+            (log/errorf "[Snowflake] %s" drop-db-sql)
             (jdbc/execute! (no-db-connection-spec) [drop-db-sql]))
           (throw e))))))
 
@@ -114,7 +115,7 @@
   [_ {:keys [database-name]}]
   (let [database-name (qualified-db-name database-name)
         sql           (format "DROP DATABASE \"%s\";" database-name)]
-    (println "[Snowflake]" sql)
+    (log/infof "[Snowflake] %s" sql)
     (jdbc/execute! (no-db-connection-spec) [sql])
     (remove-existing-dataset! database-name)))
 
diff --git a/modules/drivers/sparksql/test/metabase/test/data/sparksql.clj b/modules/drivers/sparksql/test/metabase/test/data/sparksql.clj
index 1060e0687ca68b56868d2f6a7dde22d54de5be8d..f20f6f6f7ac99c896297431bc2565db0cb29c4c4 100644
--- a/modules/drivers/sparksql/test/metabase/test/data/sparksql.clj
+++ b/modules/drivers/sparksql/test/metabase/test/data/sparksql.clj
@@ -1,6 +1,7 @@
 (ns metabase.test.data.sparksql
   (:require [clojure.java.jdbc :as jdbc]
             [clojure.string :as str]
+            [clojure.tools.logging :as log]
             [honeysql.core :as hsql]
             [honeysql.format :as hformat]
             [metabase.config :as config]
@@ -74,7 +75,7 @@
         (doseq [sql+args statements]
           (jdbc/execute! {:connection conn} sql+args {:transaction? false}))
         (catch java.sql.SQLException e
-          (println "Error inserting data:" (u/pprint-to-str 'red statements))
+          (log/infof "Error inserting data: %s" (u/pprint-to-str 'red statements))
           (jdbc/print-sql-exception-chain e)
           (throw e))))))
 
diff --git a/modules/drivers/sqlserver/test/metabase/driver/sqlserver_test.clj b/modules/drivers/sqlserver/test/metabase/driver/sqlserver_test.clj
index feb0f792952ec7e0355e6b9dede2b667baa33ca9..4a801df0058fa2b552b762bbcf07642b2efbd3ba 100644
--- a/modules/drivers/sqlserver/test/metabase/driver/sqlserver_test.clj
+++ b/modules/drivers/sqlserver/test/metabase/driver/sqlserver_test.clj
@@ -225,6 +225,7 @@
                             [(t/zoned-date-time  date time (t/zone-id "America/Los_Angeles"))
                              (t/offset-date-time (t/local-date-time date time) (t/zone-offset -8))]]]
         (let [expected (or expected t)]
+          #_{:clj-kondo/ignore [:discouraged-var]}
           (testing (format "Convert %s to SQL literal" (colorize/magenta (with-out-str (pr t))))
             (let [sql (format "SELECT %s AS t;" (unprepare/unprepare-value :sqlserver t))]
               (with-open [conn (sql-jdbc.execute/connection-with-timezone :sqlserver (mt/db) nil)
diff --git a/src/metabase/models/interface.clj b/src/metabase/models/interface.clj
index eb714e454d6dc2ebe0f731c5d0d4a7837a1646db..6839d24f482efa0b109bb82a3163ee6cf363bad9 100644
--- a/src/metabase/models/interface.clj
+++ b/src/metabase/models/interface.clj
@@ -570,7 +570,7 @@
         existing-hash  (some-> varr meta ::defmodel-hash)
         has-same-hash? (= existing-hash (hash &form))]
     (when has-same-hash?
-      (println model "has not changed, skipping redefinition"))
+      (log/infof "%s has not changed, skipping redefinition" model))
     (when-not has-same-hash?
       `(do
          ~(apply original-defmodel &form &env model args)
diff --git a/src/metabase/server/handler.clj b/src/metabase/server/handler.clj
index f03c0ffbf1f56dea90931680eb9de7dd4c4eabbf..1abe8779e9a813a313e24624c2567000dbadf190 100644
--- a/src/metabase/server/handler.clj
+++ b/src/metabase/server/handler.clj
@@ -1,6 +1,7 @@
 (ns metabase.server.handler
   "Top-level Metabase Ring handler."
   (:require
+   [clojure.tools.logging :as log]
    [metabase.config :as config]
    [metabase.server.middleware.auth :as mw.auth]
    [metabase.server.middleware.browser-cookie :as mw.browser-cookie]
@@ -85,5 +86,5 @@
   (doseq [varr  (cons #'routes/routes middleware)
           :when (instance? clojure.lang.IRef varr)]
     (add-watch varr ::reload (fn [_ _ _ _]
-                               (printf "%s changed, rebuilding %s" varr #'app)
+                               (log/infof "%s changed, rebuilding %s" varr #'app)
                                (alter-var-root #'app (constantly (apply-middleware routes/routes)))))))
diff --git a/test/metabase/driver/common/parameters/dates_test.clj b/test/metabase/driver/common/parameters/dates_test.clj
index 9a8469c788b353065538dcffde232baf6db4cf54..582d72f8907902d9f3d4cbc3fc05e57bf277f704 100644
--- a/test/metabase/driver/common/parameters/dates_test.clj
+++ b/test/metabase/driver/common/parameters/dates_test.clj
@@ -233,7 +233,7 @@
         (str frame n unit "-from-0" unit2)])
      (gen/tuple
       (gen/elements #{"next" "past"})
-      (gen/such-that #(not= % 0) gen/pos-int)
+      (gen/such-that #(not= % 0) gen/nat)
       (gen/elements time-units)
       (gen/elements time-units)))))
 
diff --git a/test/metabase/driver/mysql_test.clj b/test/metabase/driver/mysql_test.clj
index 10be20bf5705cb99892646b06bb72ba3c59c7435..11df167e76ae49bdb44ba59221aff69697fd990c 100644
--- a/test/metabase/driver/mysql_test.clj
+++ b/test/metabase/driver/mysql_test.clj
@@ -3,6 +3,7 @@
    [clojure.java.jdbc :as jdbc]
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [honeysql.core :as hsql]
    [java-time :as t]
    [metabase.config :as config]
@@ -351,10 +352,10 @@
       (testing "MySQL with SSL connectivity using PEM certificate"
         (mt/with-env-keys-renamed-by #(str/replace-first % "mb-mysql-ssl-test" "mb-mysql-test")
           (string-extracts-test/test-breakout)))
-      (println (u/format-color 'yellow
-                               "Skipping %s because %s env var is not set"
-                               "mysql-connect-with-ssl-and-pem-cert-test"
-                               "MB_MYSQL_SSL_TEST_SSL_CERT")))))
+      (log/info (u/format-color 'yellow
+                                "Skipping %s because %s env var is not set"
+                                "mysql-connect-with-ssl-and-pem-cert-test"
+                                "MB_MYSQL_SSL_TEST_SSL_CERT")))))
 
 ;; MariaDB doesn't have support for explicit JSON columns, it does it in a more SQL Server-ish way
 ;; where LONGTEXT columns are the actual JSON columns and there's JSON functions that just work on them,
diff --git a/test/metabase/driver/postgres_test.clj b/test/metabase/driver/postgres_test.clj
index c657730a943c7d5798fe881245939c7ef138d04a..d966b2beb81a8f93ec37e2f7e1c4464028e5f9bc 100644
--- a/test/metabase/driver/postgres_test.clj
+++ b/test/metabase/driver/postgres_test.clj
@@ -5,6 +5,7 @@
    [clojure.java.jdbc :as jdbc]
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [honeysql.core :as hsql]
    [metabase.config :as config]
    [metabase.driver :as driver]
@@ -276,7 +277,7 @@
                 ;; all three of these tables should appear in the metadata (including, importantly, the "main" table)
                 (is (= {:tables (set (map default-table-result ["part_vals" "part_vals_0" "part_vals_1"]))}
                        (driver/describe-database :postgres database)))))
-            (println
+            (log/warn
              (u/format-color
               'yellow
               "Skipping partitioned-table-test; Postgres major version %d doesn't support PARTITION BY" major-v))))))))
@@ -931,10 +932,10 @@
       (testing "We should be able to connect to a Postgres instance, providing our own root CA via a secret property"
         (mt/with-env-keys-renamed-by #(str/replace-first % "mb-postgres-ssl-test" "mb-postgres-test")
           (id-field-parameter-test)))
-      (println (u/format-color 'yellow
-                               "Skipping %s because %s env var is not set"
-                               "postgres-ssl-connectivity-test"
-                               "MB_POSTGRES_SSL_TEST_SSL")))))
+      (log/warn (u/format-color 'yellow
+                                "Skipping %s because %s env var is not set"
+                                "postgres-ssl-connectivity-test"
+                                "MB_POSTGRES_SSL_TEST_SSL")))))
 
 (def ^:private dummy-pem-contents
   (str "-----BEGIN CERTIFICATE-----\n"
diff --git a/test/metabase/http_client.clj b/test/metabase/http_client.clj
index ea59dc2f145e96cb7e9209c953f9f6c1b00e5080..c6c899485a9a0758b39d2e04da1eddbc5a8e504f 100644
--- a/test/metabase/http_client.clj
+++ b/test/metabase/http_client.clj
@@ -123,7 +123,7 @@
       (or (:id response)
           (throw (ex-info "Unexpected response" {:response response}))))
     (catch Throwable e
-      (println "Failed to authenticate with credentials" credentials e)
+      (log/errorf "Failed to authenticate with credentials %s %s" credentials e)
       (throw (ex-info "Failed to authenticate with credentials"
                       {:credentials credentials}
                       e)))))
diff --git a/test/metabase/query_processor/reducible_test.clj b/test/metabase/query_processor/reducible_test.clj
index 2d8aaf78e17d15eb3c5fef4c0f767fd0c32460bd..91dc0c540b236638365eb6f21166acf602148b84 100644
--- a/test/metabase/query_processor/reducible_test.clj
+++ b/test/metabase/query_processor/reducible_test.clj
@@ -21,6 +21,7 @@
      acc)
 
     ([row-count row]
+     #_{:clj-kondo/ignore [:discouraged-var]}
      (printf "ROW %d -> %s\n" (inc row-count) (pr-str row))
      (inc row-count))))
 
diff --git a/test/metabase/query_processor_test.clj b/test/metabase/query_processor_test.clj
index f568e1c4290f9e634a971413b34e68fdfa3c0c9b..a26f6c2f095e88e02fef71c27b4799be242796eb 100644
--- a/test/metabase/query_processor_test.clj
+++ b/test/metabase/query_processor_test.clj
@@ -6,6 +6,7 @@
    [clojure.set :as set]
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [hawk.init]
    [medley.core :as m]
    [metabase.db.connection :as mdb.connection]
@@ -299,7 +300,7 @@
 
   ([format-fns format-nil-values? response]
    (when (= (:status response) :failed)
-     (println "Error running query:" (u/pprint-to-str 'red response))
+     (log/warnf "Error running query: %s" (u/pprint-to-str 'red response))
      (throw (ex-info (:error response) response)))
 
    (let [format-fns (map format-rows-fn (format-rows-fns format-fns))]
diff --git a/test/metabase/query_processor_test/date_bucketing_test.clj b/test/metabase/query_processor_test/date_bucketing_test.clj
index 8901f56a695eb3881556204bdd637dc181a9c215..e39f16c778de931091dcea8d2b6ffd40f4c1526d 100644
--- a/test/metabase/query_processor_test/date_bucketing_test.clj
+++ b/test/metabase/query_processor_test/date_bucketing_test.clj
@@ -17,6 +17,7 @@
   (:require
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [java-time :as t]
    [metabase.driver :as driver]
    [metabase.driver.sql-jdbc.sync :as sql-jdbc.sync]
@@ -943,7 +944,7 @@
     ;; TODO - perhaps this should be rolled into `mt/dataset` itself -- it seems like a useful feature?
     (if (and (checkins-db-is-old? (* (.intervalSeconds dataset) 5)) *recreate-db-if-stale?*)
       (binding [*recreate-db-if-stale?* false]
-        (printf "DB for %s is stale! Deleteing and running test again\n" dataset)
+        (log/infof "DB for %s is stale! Deleteing and running test again\n" dataset)
         (db/delete! Database :id (mt/id))
         (apply count-of-grouping dataset field-grouping relative-datetime-args))
       (let [results (mt/run-mbql-query checkins
diff --git a/test/metabase/test.clj b/test/metabase/test.clj
index 08a207f0e567e4e90d58a34405a555e49edfd37c..974d2149d2aa4679f37c8daba959652f716814b4 100644
--- a/test/metabase/test.clj
+++ b/test/metabase/test.clj
@@ -28,6 +28,7 @@
    [metabase.query-processor.reducible :as qp.reducible]
    [metabase.query-processor.test-util :as qp.test-util]
    [metabase.server.middleware.session :as mw.session]
+   [metabase.shared.util.log :as log]
    [metabase.test-runner.assert-exprs :as test-runner.assert-exprs]
    [metabase.test.data :as data]
    [metabase.test.data.datasets :as datasets]
@@ -371,7 +372,7 @@
                                  (when run (run))
                                  (qp.context/reducef rff context (assoc metadata :pre query) rows)
                                  (catch Throwable e
-                                   (println "Error in test-qp-middleware runf:" e)
+                                   (log/errorf "Error in test-qp-middleware runf: %s" e)
                                    (throw e))))}
                    context)]
      (if async?
diff --git a/test/metabase/test/data/env.clj b/test/metabase/test/data/env.clj
index f3aa6e5409113dacb7bab041cce22701426eb829..5e8f5e91e541761e9d9d6e343cacd1398dcd50a7 100644
--- a/test/metabase/test/data/env.clj
+++ b/test/metabase/test/data/env.clj
@@ -10,6 +10,7 @@
     # just test against :h2 (default)
     DRIVERS=h2"
   (:require
+   [clojure.tools.logging :as log]
    [colorize.core :as colorize]
    [metabase.test.data.env.impl :as tx.env.impl]
    [metabase.test.initialize :as initialize]))
@@ -18,7 +19,7 @@
   (delay
     (let [drivers (tx.env.impl/get-test-drivers)]
       ;; this is println on purpose so it always shows up regardless of log level
-      (println (colorize/cyan "Running QP tests against these drivers: " drivers))
+      (log/info (colorize/cyan "Running QP tests against these drivers: " drivers))
       (when-not (= drivers #{:h2})
         (initialize/initialize-if-needed! :plugins))
       drivers)))
diff --git a/test/metabase/test/data/env/impl.clj b/test/metabase/test/data/env/impl.clj
index 4f5ff905dca187268c9fd09bace12ad5d615c131..4c1190da77ab115481f63937896d60f111f68474 100644
--- a/test/metabase/test/data/env/impl.clj
+++ b/test/metabase/test/data/env/impl.clj
@@ -2,11 +2,12 @@
   (:require
    [clojure.string :as str]
    [environ.core :refer [env]]
+   [metabase.shared.util.log :as log]
    [metabase.util :as u]))
 
 (defn- get-drivers-from-env []
   (when (seq (env :engines))
-    (println
+    (log/error
      (u/format-color 'red
          "The env var ENGINES is no longer supported. Please specify drivers to run tests against with DRIVERS instead.")))
   (when-let [env-drivers (some-> (env :drivers) u/lower-case-en)]
diff --git a/test/metabase/test/data/sql_jdbc/execute.clj b/test/metabase/test/data/sql_jdbc/execute.clj
index 1918cd982795a18d73a849872cdf8a5cb55e9ca4..3597b71172ebbe3f28659911b9154d14c33a2bbb 100644
--- a/test/metabase/test/data/sql_jdbc/execute.clj
+++ b/test/metabase/test/data/sql_jdbc/execute.clj
@@ -28,14 +28,14 @@
         (try
           (execute! (spec/dbdef->spec driver context dbdef) sql)
           (catch SQLException e
-            (println "Error executing SQL:" sql)
-            (printf "Caught SQLException:\n%s\n"
-                    (with-out-str (jdbc/print-sql-exception-chain e)))
+            (log/errorf "Error executing SQL: %s" sql)
+            (log/errorf "Caught SQLException:\n%s\n"
+                        (with-out-str (jdbc/print-sql-exception-chain e)))
             (throw e))
           (catch Throwable e
-            (println "Error executing SQL:" sql)
-            (printf "Caught Exception: %s %s\n%s\n" (class e) (.getMessage e)
-                    (with-out-str (.printStackTrace e)))
+            (log/errorf "Error executing SQL: %s" sql)
+            (log/errorf "Caught Exception: %s %s\n%s\n" (class e) (.getMessage e)
+                        (with-out-str (.printStackTrace e)))
             (throw e)))))))
 
 (defn sequentially-execute-sql!
diff --git a/test/metabase/test/data/sql_jdbc/load_data.clj b/test/metabase/test/data/sql_jdbc/load_data.clj
index 0321147215c13aa90bec3b709ad5076e1da920d6..a2bb421a65896a2a2e67dd9a0b0de81545fc61e2 100644
--- a/test/metabase/test/data/sql_jdbc/load_data.clj
+++ b/test/metabase/test/data/sql_jdbc/load_data.clj
@@ -199,7 +199,7 @@
           (jdbc/execute! spec sql+args {:set-parameters (fn [stmt params]
                                                           (sql-jdbc.execute/set-parameters! driver stmt params))}))
         (catch SQLException e
-          (println (u/format-color 'red "INSERT FAILED: \n%s\n" (pr-str statements)))
+          (log/error (u/format-color 'red "INSERT FAILED: \n%s\n" (pr-str statements)))
           (jdbc/print-sql-exception-chain e)
           (throw e))))))
 
diff --git a/test/metabase/test/generate.clj b/test/metabase/test/generate.clj
index 6111e984fe27bce985546750b719e5bce241a648..8ee95336c74f920f14d3c940ae7b2fb80263b595 100644
--- a/test/metabase/test/generate.clj
+++ b/test/metabase/test/generate.clj
@@ -2,6 +2,7 @@
   (:require
    [clojure.spec.alpha :as s]
    [clojure.test.check.generators :as gen]
+   [clojure.tools.logging :as log]
    [java-time :as t]
    [metabase.mbql.util :as mbql.u]
    [metabase.models :refer [Activity Card Collection Dashboard DashboardCard DashboardCardSeries Database
@@ -348,7 +349,7 @@
                                  sm-db
                                  (assoc visit-opts :visit-val (:spec-gen attrs))))
                     (catch Throwable e
-                      (println e)))))
+                      (log/error e)))))
       (rs/attr-map :insert!)))
 
 (defn generate-horror-show! []
diff --git a/test/metabase/test/initialize/web_server.clj b/test/metabase/test/initialize/web_server.clj
index 8e79097160ed0f2d736a7c8f11f13f807ba445db..74e9457ff57c61bad8e5e09a83edcf61077085a6 100644
--- a/test/metabase/test/initialize/web_server.clj
+++ b/test/metabase/test/initialize/web_server.clj
@@ -12,20 +12,20 @@
    (try
      (#'handler/app request)
      (catch Throwable e
-       (println "ERROR HANDLING REQUEST! <sync>" request)
-       (println e)
+       (log/errorf "ERROR HANDLING REQUEST! <sync> %s" request)
+       (log/error e)
        (throw e))))
 
   ([request respond raise]
    (letfn [(raise' [e]
-             (println "ERROR HANDLING REQUEST! <async raise>" request)
-             (println e)
+             (log/errorf "ERROR HANDLING REQUEST! <async raise> %s" request)
+             (log/error e)
              (raise e))]
      (try
        (#'handler/app request respond raise')
        (catch Throwable e
-         (println "ERROR HANDLING REQUEST! <async thrown>" request)
-         (println e)
+         (log/errorf "ERROR HANDLING REQUEST! <async thrown> %s" request)
+         (log/error e)
          (throw e))))))
 
 (defn init! []
diff --git a/test/metabase/test/util.clj b/test/metabase/test/util.clj
index b9d71db08a3e6708b812120061feaa68dfd8a5f5..c13144f878e8443258593ac0d285c255ecd7cf64 100644
--- a/test/metabase/test/util.clj
+++ b/test/metabase/test/util.clj
@@ -6,6 +6,7 @@
    [clojure.set :as set]
    [clojure.string :as str]
    [clojure.test :refer :all]
+   [clojure.tools.logging :as log]
    [clojure.walk :as walk]
    [clojurewerkz.quartzite.scheduler :as qs]
    [colorize.core :as colorize]
@@ -305,7 +306,7 @@
    model-var
    ::reload
    (fn [_key _reference _old-state _new-state]
-     (println (format "%s changed, reloading with-temp-defaults" model-var))
+     (log/infof "%s changed, reloading with-temp-defaults" model-var)
      (set-with-temp-defaults!))))
 
 
diff --git a/test/metabase/test/util/log.clj b/test/metabase/test/util/log.clj
index d0c63c26cde077f2aee8a1a8040997503e46dbe4..897be54129ea43a408e1ecf23cff3a125f6a7e7a 100644
--- a/test/metabase/test/util/log.clj
+++ b/test/metabase/test/util/log.clj
@@ -92,6 +92,7 @@
                          (.getFilter parent-logger))]
       (.addLogger (configuration) (logger-name a-namespace) new-logger)
       (.updateLoggers (logger-context))
+      #_{:clj-kondo/ignore [:discouraged-var]}
       (println "Created a new logger for" (logger-name a-namespace)))))
 
 (s/defn set-ns-log-level!
diff --git a/test/metabase/util_test.clj b/test/metabase/util_test.clj
index e0da180a8a36dda8bcd42e67670fdb1abd3a4e22..064769d14c2edc66d395b64fff7139b5fc8cc0fd 100644
--- a/test/metabase/util_test.clj
+++ b/test/metabase/util_test.clj
@@ -329,7 +329,7 @@
               (shuffle (range 30))))))
 
 (defspec sorted-take-test-size
-  (prop/for-all [coll (gen/list (gen/tuple gen/int gen/string))
+  (prop/for-all [coll (gen/list (gen/tuple gen/small-integer gen/string))
                  size (gen/fmap inc gen/nat)]
     (= (vec (take-last size (sort coll)))
        (transduce (map identity)
@@ -337,7 +337,7 @@
                   coll))))
 
 (defspec sorted-take-test-comparator
-  (prop/for-all [coll (gen/list (gen/fmap (fn [x] {:score x}) gen/int))
+  (prop/for-all [coll (gen/list (gen/fmap (fn [x] {:score x}) gen/small-integer))
                  size (gen/fmap inc gen/nat)]
     (let [coll    (shuffle coll)
           kompare (fn [{score-1 :score} {score-2 :score}]
@@ -362,7 +362,7 @@
     true  "cam.saul+1@metabase.com"   "metabase.com"))
 
 (defspec pick-first-test 100
-  (prop/for-all [coll (gen/list gen/int)]
+  (prop/for-all [coll (gen/list gen/small-integer)]
     (let [result (u/pick-first pos? coll)]
       (or (and (nil? result)
                (every? (complement pos?) coll))