This is an automated email from the ASF dual-hosted git repository.
jiayu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/sedona-db.git
The following commit(s) were added to refs/heads/main by this push:
new 53260de chore: add Scarf package to track usage (#35)
53260de is described below
commit 53260de4e9536158a6aead6c2b63d405f5cf1f30
Author: Jia Yu <[email protected]>
AuthorDate: Sat Sep 6 22:57:35 2025 -0700
chore: add Scarf package to track usage (#35)
---
python/sedonadb/python/sedonadb/_scarf.py | 58 +++++++++++++++++++++++++++
python/sedonadb/python/sedonadb/adbc.py | 4 ++
python/sedonadb/python/sedonadb/context.py | 4 ++
python/sedonadb/python/sedonadb/dbapi.py | 5 +++
rust/sedona/src/context.rs | 6 +++
rust/sedona/src/lib.rs | 1 +
rust/sedona/src/scarf.rs | 63 ++++++++++++++++++++++++++++++
sedona-cli/src/main.rs | 3 ++
8 files changed, 144 insertions(+)
diff --git a/python/sedonadb/python/sedonadb/_scarf.py
b/python/sedonadb/python/sedonadb/_scarf.py
new file mode 100644
index 0000000..024945c
--- /dev/null
+++ b/python/sedonadb/python/sedonadb/_scarf.py
@@ -0,0 +1,58 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""Scarf analytics utility functions."""
+
+import os
+import platform
+import threading
+import urllib.request
+
+
+def make_scarf_call(language: str) -> None:
+ """Make a call to Scarf for usage analytics.
+
+ Args:
+ language: The language identifier (e.g., 'python', 'adbc', 'dbapi')
+ """
+
+ def _scarf_request():
+ try:
+ # Check for user opt-out
+ if (
+ os.environ.get("SCARF_NO_ANALYTICS") is not None
+ or os.environ.get("DO_NOT_TRACK") is not None
+ ):
+ return
+
+ # Detect architecture and OS
+ arch = platform.machine().lower().replace(" ", "_")
+ os_name = platform.system().lower().replace(" ", "_")
+
+ # Construct Scarf URL
+ scarf_url = (
+
f"https://sedona.gateway.scarf.sh/sedona-db/{arch}/{os_name}/{language}"
+ )
+
+ # Make the request in a non-blocking way
+ urllib.request.urlopen(scarf_url, timeout=1)
+ except Exception:
+ # Silently ignore any errors - we don't want Scarf calls to break
user code
+ pass
+
+ # Run in a separate thread to avoid blocking
+ thread = threading.Thread(target=_scarf_request, daemon=True)
+ thread.start()
diff --git a/python/sedonadb/python/sedonadb/adbc.py
b/python/sedonadb/python/sedonadb/adbc.py
index 0773c17..25176a5 100644
--- a/python/sedonadb/python/sedonadb/adbc.py
+++ b/python/sedonadb/python/sedonadb/adbc.py
@@ -21,6 +21,10 @@ from sedonadb import _lib
def connect() -> adbc_driver_manager.AdbcDatabase:
"""Create a low level ADBC connection to Sedona."""
+ # Make Scarf call for usage analytics
+ from ._scarf import make_scarf_call
+
+ make_scarf_call("adbc")
return adbc_driver_manager.AdbcDatabase(
driver=_lib.__file__, entrypoint="AdbcSedonadbDriverInit"
)
diff --git a/python/sedonadb/python/sedonadb/context.py
b/python/sedonadb/python/sedonadb/context.py
index 6531b86..b981057 100644
--- a/python/sedonadb/python/sedonadb/context.py
+++ b/python/sedonadb/python/sedonadb/context.py
@@ -149,6 +149,10 @@ class SedonaContext:
def connect() -> SedonaContext:
"""Create a new [SedonaContext][sedonadb.context.SedonaContext]"""
+ # Make Scarf call for usage analytics
+ from ._scarf import make_scarf_call
+
+ make_scarf_call("python")
return SedonaContext()
diff --git a/python/sedonadb/python/sedonadb/dbapi.py
b/python/sedonadb/python/sedonadb/dbapi.py
index cfa8a43..bd0489d 100644
--- a/python/sedonadb/python/sedonadb/dbapi.py
+++ b/python/sedonadb/python/sedonadb/dbapi.py
@@ -21,6 +21,11 @@ import sedonadb.adbc
def connect(**kwargs) -> "Connection":
"""Connect to Sedona via ADBC."""
+ # Make Scarf call for usage analytics
+ from ._scarf import make_scarf_call
+
+ make_scarf_call("dbapi")
+
db = None
conn = None
diff --git a/rust/sedona/src/context.rs b/rust/sedona/src/context.rs
index 68b87bb..4096b04 100644
--- a/rust/sedona/src/context.rs
+++ b/rust/sedona/src/context.rs
@@ -67,6 +67,9 @@ pub struct SedonaContext {
impl SedonaContext {
/// Creates a new context with default options
pub fn new() -> Self {
+ // Make Scarf call for usage analytics
+ crate::scarf::make_scarf_call("rust");
+
// This will panic only if the default build settings are
// incorrect which we test!
Self::new_from_context(SessionContext::new()).unwrap()
@@ -77,6 +80,9 @@ impl SedonaContext {
/// Initializes a context from the current environment and registers access
/// to the local file system.
pub async fn new_local_interactive() -> Result<Self> {
+ // Make Scarf call for usage analytics
+ crate::scarf::make_scarf_call("rust");
+
// These three objects enable configuring various elements of the
runtime.
// Eventually we probably want to have a common set of configuration
parameters
// exposed via the CLI/Python as arguments, via ADBC as connection
options,
diff --git a/rust/sedona/src/lib.rs b/rust/sedona/src/lib.rs
index 52b5438..c31de9c 100644
--- a/rust/sedona/src/lib.rs
+++ b/rust/sedona/src/lib.rs
@@ -22,4 +22,5 @@ mod object_storage;
pub mod random_geometry_provider;
pub mod reader;
pub mod record_batch_reader_provider;
+pub mod scarf;
pub mod show;
diff --git a/rust/sedona/src/scarf.rs b/rust/sedona/src/scarf.rs
new file mode 100644
index 0000000..201ce2f
--- /dev/null
+++ b/rust/sedona/src/scarf.rs
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+/// Make a call to Scarf for usage analytics.
+///
+/// # Arguments
+///
+/// * `language` - The language identifier (e.g., "rust", "cli")
+pub fn make_scarf_call(language: &str) {
+ let language = language.to_string();
+ std::thread::spawn(move || {
+ let _ = scarf_request(&language);
+ });
+}
+
+fn scarf_request(language: &str) -> Result<(), Box<dyn std::error::Error +
Send + Sync>> {
+ // Check for user opt-out
+ if std::env::var("SCARF_NO_ANALYTICS").is_ok() ||
std::env::var("DO_NOT_TRACK").is_ok() {
+ return Ok(());
+ }
+
+ // Detect architecture and OS
+ let arch = std::env::consts::ARCH.to_lowercase().replace(' ', "_");
+ let os = std::env::consts::OS.to_lowercase().replace(' ', "_");
+
+ // Construct Scarf URL
+ let scarf_url =
format!("https://sedona.gateway.scarf.sh/sedona-db/{arch}/{os}/{language}");
+
+ // Make the request using std::net::TcpStream for a simple HTTP GET
+ if let Ok(url) = url::Url::parse(&scarf_url) {
+ if let Some(host) = url.host_str() {
+ let port = url.port().unwrap_or(443);
+ let path = url.path();
+
+ // Try to make a simple HTTP request
+ if let Ok(addr) =
format!("{host}:{port}").parse::<std::net::SocketAddr>() {
+ if let Ok(mut stream) =
+ std::net::TcpStream::connect_timeout(&addr,
std::time::Duration::from_secs(1))
+ {
+ let request =
+ format!("GET {path} HTTP/1.1\r\nHost:
{host}\r\nConnection: close\r\n\r\n");
+ let _ = std::io::Write::write_all(&mut stream,
request.as_bytes());
+ }
+ }
+ }
+ }
+
+ Ok(())
+}
diff --git a/sedona-cli/src/main.rs b/sedona-cli/src/main.rs
index bcfd477..0cd11aa 100644
--- a/sedona-cli/src/main.rs
+++ b/sedona-cli/src/main.rs
@@ -128,6 +128,9 @@ async fn main_inner() -> Result<()> {
println!("Sedona CLI v{DATAFUSION_CLI_VERSION}");
}
+ // Make Scarf call for usage analytics
+ sedona::scarf::make_scarf_call("cli");
+
if let Some(ref path) = args.data_path {
let p = Path::new(path);
env::set_current_dir(p).unwrap();