Fix failing constraint
This commit is contained in:
@@ -55,9 +55,10 @@ impl Database {
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- Main table with normalized foreign keys and integer timestamp
|
-- Main table with normalized foreign keys and integer timestamp
|
||||||
|
-- timestamp_ms stores milliseconds since epoch for uniqueness
|
||||||
CREATE TABLE IF NOT EXISTS signature_entries (
|
CREATE TABLE IF NOT EXISTS signature_entries (
|
||||||
session_id TEXT NOT NULL,
|
session_id TEXT NOT NULL,
|
||||||
timestamp INTEGER NOT NULL,
|
timestamp_ms INTEGER NOT NULL,
|
||||||
app_id INTEGER NOT NULL REFERENCES apps(id),
|
app_id INTEGER NOT NULL REFERENCES apps(id),
|
||||||
version_id INTEGER NOT NULL REFERENCES versions(id),
|
version_id INTEGER NOT NULL REFERENCES versions(id),
|
||||||
offline_login_usage INTEGER,
|
offline_login_usage INTEGER,
|
||||||
@@ -70,7 +71,7 @@ impl Database {
|
|||||||
model_id INTEGER REFERENCES models(id),
|
model_id INTEGER REFERENCES models(id),
|
||||||
device_id INTEGER REFERENCES devices(id),
|
device_id INTEGER REFERENCES devices(id),
|
||||||
password_autofill_usage INTEGER,
|
password_autofill_usage INTEGER,
|
||||||
PRIMARY KEY (session_id, timestamp)
|
PRIMARY KEY (session_id, timestamp_ms)
|
||||||
) WITHOUT ROWID;
|
) WITHOUT ROWID;
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_session_id ON signature_entries(session_id);
|
CREATE INDEX IF NOT EXISTS idx_session_id ON signature_entries(session_id);
|
||||||
@@ -96,7 +97,7 @@ impl Database {
|
|||||||
let mut insert_stmt = tx.prepare_cached(
|
let mut insert_stmt = tx.prepare_cached(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO signature_entries (
|
INSERT INTO signature_entries (
|
||||||
session_id, timestamp, app_id, version_id,
|
session_id, timestamp_ms, app_id, version_id,
|
||||||
offline_login_usage, is_password_autofill_enabled, camera_roll_usage,
|
offline_login_usage, is_password_autofill_enabled, camera_roll_usage,
|
||||||
os_id, app_name_id, touch_id, is_offline_login_enabled,
|
os_id, app_name_id, touch_id, is_offline_login_enabled,
|
||||||
model_id, device_id, password_autofill_usage
|
model_id, device_id, password_autofill_usage
|
||||||
@@ -114,7 +115,7 @@ impl Database {
|
|||||||
|
|
||||||
insert_stmt.execute(params![
|
insert_stmt.execute(params![
|
||||||
entry.session_id,
|
entry.session_id,
|
||||||
entry.timestamp.and_utc().timestamp(),
|
entry.timestamp_ms,
|
||||||
app_id,
|
app_id,
|
||||||
version_id,
|
version_id,
|
||||||
entry.offline_login_usage,
|
entry.offline_login_usage,
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ use std::sync::LazyLock;
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct SignatureEntry {
|
pub struct SignatureEntry {
|
||||||
pub session_id: String,
|
pub session_id: String,
|
||||||
pub timestamp: NaiveDateTime,
|
/// Timestamp as milliseconds since Unix epoch (UTC)
|
||||||
|
pub timestamp_ms: i64,
|
||||||
pub app: String,
|
pub app: String,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
pub offline_login_usage: Option<i64>,
|
pub offline_login_usage: Option<i64>,
|
||||||
@@ -39,7 +40,7 @@ pub enum ParsedMessage {
|
|||||||
static SESSION_ID_RE: LazyLock<Regex> =
|
static SESSION_ID_RE: LazyLock<Regex> =
|
||||||
LazyLock::new(|| Regex::new(r"sessionId=([^,\s]+)").unwrap());
|
LazyLock::new(|| Regex::new(r"sessionId=([^,\s]+)").unwrap());
|
||||||
static DATETIME_RE: LazyLock<Regex> =
|
static DATETIME_RE: LazyLock<Regex> =
|
||||||
LazyLock::new(|| Regex::new(r#"dt="(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})"#).unwrap());
|
LazyLock::new(|| Regex::new(r#"dt="(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})(?:,(\d{3}))?"#).unwrap());
|
||||||
static CORRELATION_ID_RE: LazyLock<Regex> =
|
static CORRELATION_ID_RE: LazyLock<Regex> =
|
||||||
LazyLock::new(|| Regex::new(r"correlationId=([^,\s]+)").unwrap());
|
LazyLock::new(|| Regex::new(r"correlationId=([^,\s]+)").unwrap());
|
||||||
static SIGNATURE_RE: LazyLock<Regex> =
|
static SIGNATURE_RE: LazyLock<Regex> =
|
||||||
@@ -84,15 +85,8 @@ impl SignatureParser {
|
|||||||
.map(|m| m.as_str().to_string())
|
.map(|m| m.as_str().to_string())
|
||||||
.ok_or_else(|| anyhow!("Missing sessionId"))?;
|
.ok_or_else(|| anyhow!("Missing sessionId"))?;
|
||||||
|
|
||||||
// Extract timestamp
|
// Extract timestamp as milliseconds
|
||||||
let datetime_str = DATETIME_RE
|
let timestamp_ms = extract_timestamp_ms(line)?;
|
||||||
.captures(line)
|
|
||||||
.and_then(|c| c.get(1))
|
|
||||||
.map(|m| m.as_str())
|
|
||||||
.ok_or_else(|| anyhow!("Missing datetime"))?;
|
|
||||||
|
|
||||||
let timestamp = NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S")
|
|
||||||
.map_err(|e| anyhow!("Invalid datetime format: {}", e))?;
|
|
||||||
|
|
||||||
// Extract signature details
|
// Extract signature details
|
||||||
let caps = SIGNATURE_RE
|
let caps = SIGNATURE_RE
|
||||||
@@ -109,7 +103,7 @@ impl SignatureParser {
|
|||||||
|
|
||||||
let entry = SignatureEntry {
|
let entry = SignatureEntry {
|
||||||
session_id,
|
session_id,
|
||||||
timestamp,
|
timestamp_ms,
|
||||||
app,
|
app,
|
||||||
version,
|
version,
|
||||||
offline_login_usage: parse_number(&details, "offlineLoginUsage"),
|
offline_login_usage: parse_number(&details, "offlineLoginUsage"),
|
||||||
@@ -143,7 +137,7 @@ impl MessageParser for MobileClientIosParser {
|
|||||||
|
|
||||||
impl MobileClientIosParser {
|
impl MobileClientIosParser {
|
||||||
fn parse_mobile_ios_line(&self, line: &str) -> Result<ParsedMessage> {
|
fn parse_mobile_ios_line(&self, line: &str) -> Result<ParsedMessage> {
|
||||||
let timestamp = extract_timestamp(line)?;
|
let timestamp_ms = extract_timestamp_ms(line)?;
|
||||||
let session_id = extract_correlation_id(line)?;
|
let session_id = extract_correlation_id(line)?;
|
||||||
|
|
||||||
let caps = MOBILE_IOS_RE
|
let caps = MOBILE_IOS_RE
|
||||||
@@ -158,7 +152,7 @@ impl MobileClientIosParser {
|
|||||||
|
|
||||||
let entry = SignatureEntry {
|
let entry = SignatureEntry {
|
||||||
session_id,
|
session_id,
|
||||||
timestamp,
|
timestamp_ms,
|
||||||
app,
|
app,
|
||||||
version,
|
version,
|
||||||
offline_login_usage: None,
|
offline_login_usage: None,
|
||||||
@@ -192,7 +186,7 @@ impl MessageParser for MobileClientAndroidParser {
|
|||||||
|
|
||||||
impl MobileClientAndroidParser {
|
impl MobileClientAndroidParser {
|
||||||
fn parse_mobile_android_line(&self, line: &str) -> Result<ParsedMessage> {
|
fn parse_mobile_android_line(&self, line: &str) -> Result<ParsedMessage> {
|
||||||
let timestamp = extract_timestamp(line)?;
|
let timestamp_ms = extract_timestamp_ms(line)?;
|
||||||
let session_id = extract_correlation_id(line)?;
|
let session_id = extract_correlation_id(line)?;
|
||||||
|
|
||||||
let caps = MOBILE_ANDROID_RE
|
let caps = MOBILE_ANDROID_RE
|
||||||
@@ -207,7 +201,7 @@ impl MobileClientAndroidParser {
|
|||||||
|
|
||||||
let entry = SignatureEntry {
|
let entry = SignatureEntry {
|
||||||
session_id,
|
session_id,
|
||||||
timestamp,
|
timestamp_ms,
|
||||||
app,
|
app,
|
||||||
version,
|
version,
|
||||||
offline_login_usage: None,
|
offline_login_usage: None,
|
||||||
@@ -226,16 +220,22 @@ impl MobileClientAndroidParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract timestamp from log line
|
/// Extract timestamp from log line as milliseconds since Unix epoch
|
||||||
fn extract_timestamp(line: &str) -> Result<NaiveDateTime> {
|
fn extract_timestamp_ms(line: &str) -> Result<i64> {
|
||||||
let datetime_str = DATETIME_RE
|
let caps = DATETIME_RE
|
||||||
.captures(line)
|
.captures(line)
|
||||||
.and_then(|c| c.get(1))
|
|
||||||
.map(|m| m.as_str())
|
|
||||||
.ok_or_else(|| anyhow!("Missing datetime"))?;
|
.ok_or_else(|| anyhow!("Missing datetime"))?;
|
||||||
|
|
||||||
NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S")
|
let datetime_str = caps.get(1).map(|m| m.as_str()).unwrap();
|
||||||
.map_err(|e| anyhow!("Invalid datetime format: {}", e))
|
let millis: i64 = caps
|
||||||
|
.get(2)
|
||||||
|
.map(|m| m.as_str().parse().unwrap_or(0))
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let dt = NaiveDateTime::parse_from_str(datetime_str, "%Y-%m-%d %H:%M:%S")
|
||||||
|
.map_err(|e| anyhow!("Invalid datetime format: {}", e))?;
|
||||||
|
|
||||||
|
Ok(dt.and_utc().timestamp_millis() + millis)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract correlation ID as session ID for mobile client logs
|
/// Extract correlation ID as session ID for mobile client logs
|
||||||
|
|||||||
Reference in New Issue
Block a user