הטמעת איסוף לוגים דיאגנוסטיים באפליקציות מובייל

כאשר אפליקציה קורסת רק אצל משתמש מסוים בעוד שסביבת הבדיקות פועלת כראוי, לוגים דיאגנוסטיים הם הכרחיים. אנו מיישמים מערכת איסוף לוגים מלאה—מהזיכרון הפנימי ועד לייצוא לפי דרישה—כדי שתוכלו לאתר במהירות את הגורמים לתקלות. הצוות שלנו מטפל בכל התהליך: בדיקת צרכים, פיתוח, הטמעה ותמיכה שוטפת, ומספק פתרון אמין שגדל עם העסק שלכם.

פיתוח ותמיכה בכל סוגי היישומים הניידים:

יישומים ניידים למידע ובידור
אפליקציות חדשות, משחקים, מדריכים, קטלוגים מקוונים, אפליקציות מזג אוויר, אפליקציות כושר ובריאות, אפליקציות נסיעות, אפליקציות חינוכיות, רשתות חברתיות ומסנג'רים, חידונים, בלוגים ופודקאסטים, פורומים, אגרגטורים
יישומים ניידים למסחר אלקטרוני
חנויות מקוונות, אפליקציות B2B, מרקטפלייסים, בורסות מקוונות, שירותי קאשבק, בורסות, פלטפורמות דרופשיפינג, תוכניות נאמנות, משלוחי מזון ומוצרים, מערכות תשלום.
יישומים ניידים לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, ניהול פרויקטים, כלים לצוותי מכירות, ניהול פיננסי, ניהול ייצור, ניהול לוגיסטיקה ומשלוחים, ניהול משאבי אנוש, מערכות ניטור נתונים
יישומים ניידים לשירותים אלקטרוניים
פלטפורמות מודעות מסווגות, בתי ספר מקוונים, בתי קולנוע מקוונים, פלטפורמות שירות אלקטרוניות, פלטפורמות קאשבק, אירוח וידאו, פורטלים נושאיים, פלטפורמות הזמנות ותזמון מקוונות, פלטפורמות מסחר מקוונות

אלה הם רק חלק מסוגי היישומים הניידים שאנו עובדים איתם, ולכל אחד מהם עשויים להיות מאפיינים ופונקציונליות ספציפיים משלו, המותאמים לצרכים ולמטרות הספציפיות של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 1734 השירותים
הטמעת איסוף לוגים דיאגנוסטיים באפליקציות מובייל
בינוני
~2-3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית מובייל עבור FEEDME
    פיתוח אפליקציית מובייל עבור FEEDME
    971
  • פיתוח אפליקציית מובייל עבור XOOMER
    פיתוח אפליקציית מובייל עבור XOOMER
    869
  • פיתוח אפליקציית מובייל עבור RHL
    פיתוח אפליקציית מובייל עבור RHL
    1289
  • פיתוח אפליקציית מובייל עבור ZIPPY
    פיתוח אפליקציית מובייל עבור ZIPPY
    1143
  • פיתוח אפליקציית מובייל עבור Affhome
    פיתוח אפליקציית מובייל עבור Affhome
    1076
  • פיתוח אפליקציית מובייל עבור חברת FLAVORS
    פיתוח אפליקציית מובייל עבור חברת FLAVORS
    677

הטמעת איסוף לוגים דיאגנוסטיים באפליקציות מובייל

דיווחי משתמשים: "האפליקציה קורסת בעת שליחת טופס." אתה בודק — והיא עובדת מצוין בסימולטור. ללא לוגים דיאגנוסטיים, תרחיש זה הוא כאב ראש טיפוסי. ב-70% מהמקרים, באגים תלויים במצב המכשיר ואינם ניתנים לשחזור בסביבת בדיקה. צוותים מבזבזים עד 3 ימים באיסוף לוגים מ-logcat, צילומי מסך של לקוחות וראיונות ידניים. אנו מיישמים מערכת איסוף לוגים דיאגנוסטיים מוכנה לשימוש: מחיץ בזיכרון ועד ייצוא לפי דרישה. הניסיון שלנו: 50+ פרויקטי דיאגנוסטיקה למובייל, 5 שנים בשוק. אנו מבטיחים הפחתה של 30% בזמן פתרון כרטיסי תמיכה. קבלו ייעוץ על הטמעה — צרו קשר.

מדוע לוגים דיאגנוסטיים קריטיים לאפליקציות מובייל

איסוף לוגים אינו מותרות אלא כלי תמיכה חובה. בלעדיו, כל תקרית דורשת שחזור ידני. כתוצאה מכך, עד 60% מהזמן מושקע בחיפוש אחר הגורם השורשי. חיץ בזיכרון לוכד את 500 האירועים האחרונים לפני קריסה — מספיק כדי לשחזר 5–10 שניות של פעילות האפליקציה. לפי תיעוד Apple, OSLog מספק איסוף מובנה עם השפעה מינימלית על הביצועים. באנדרואיד, Timber עם Tree מותאם אישית מציע שליטה דומה.

כיצד לארגן איסוף לוגים כראוי

ארכיטקטורת לוגים

כתיבת קבצים קבועה בכל קריאת לוג היא יקרה. במקום זאת, שמרו חיץ טבעתי בזיכרון ושטפו לדיסק רק בעת דיאגנוסטיקה או קריסה:

class LogBuffer(private val capacity: Int = 500) {
    private val buffer = ArrayDeque<LogEntry>(capacity)

    @Synchronized
    fun add(level: LogLevel, tag: String, message: String) {
        if (buffer.size >= capacity) buffer.removeFirst()
        buffer.addLast(
            LogEntry(
                timestamp = System.currentTimeMillis(),
                level = level,
                tag = tag,
                message = message
            )
        )
    }

    @Synchronized
    fun getLast(count: Int): List<LogEntry> = buffer.takeLast(minOf(count, buffer.size))
}

500 רשומות מספיקות כדי לשחזר את הדקות האחרונות של הפעולה. יותר מכך הוא מיותר וצורך זיכרון.

class DiagnosticTree(private val buffer: LogBuffer) : Timber.Tree() {
    override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
        val level = when (priority) {
            Log.DEBUG -> LogLevel.DEBUG
            Log.INFO -> LogLevel.INFO
            Log.WARN -> LogLevel.WARN
            Log.ERROR -> LogLevel.ERROR
            else -> LogLevel.VERBOSE
        }
        buffer.add(level, tag ?: "App", message)
        if (BuildConfig.DEBUG) super.log(priority, tag, message, t)
    }
}

// Application.onCreate()
Timber.plant(DiagnosticTree(logBuffer))
Timber.plant(if (BuildConfig.DEBUG) Timber.DebugTree() else SilentTree())

iOS — OSLog + חיץ בזיכרון

class DiagnosticLogger {
    private let osLog = Logger(subsystem: "com.example.app", category: "diagnostic")
    private var buffer: [LogEntry] = []
    private let maxEntries = 500
    private let queue = DispatchQueue(label: "logger", qos: .utility)

    func log(_ message: String, level: LogLevel = .info, file: String = #file, line: Int = #line) {
        let entry = LogEntry(
            timestamp: Date(),
            level: level,
            message: message,
            location: "\(URL(fileURLWithPath: file).lastPathComponent):\(line)"
        )
        queue.async { [weak self] in
            guard let self else { return }
            if self.buffer.count >= self.maxEntries {
                self.buffer.removeFirst()
            }
            self.buffer.append(entry)
        }
        osLog.log(level: level.osLogType, "\(message)")
    }
}

class LogBuffer(private val capacity: Int = 500) { private val buffer = ArrayDeque<LogEntry>(capacity) @Synchronized fun add(level: LogLevel, tag: String, message: String) { if (buffer.size >= capacity) buffer.removeFirst() buffer.addLast(LogEntry( timestamp = System.currentTimeMillis(), level = level, tag = tag, message = message )) } @Synchronized fun getLast(count: Int): List<LogEntry> = buffer.takeLast(minOf(count, buffer.size)) } ו-class DiagnosticTree(private val buffer: LogBuffer) : Timber.Tree() { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { val level = when (priority) { Log.DEBUG -> LogLevel.DEBUG Log.INFO -> LogLevel.INFO Log.WARN -> LogLevel.WARN Log.ERROR -> LogLevel.ERROR else -> LogLevel.VERBOSE } buffer.add(level, tag ?: "App", message) if (BuildConfig.DEBUG) super.log(priority, tag, message, t) } } // Application.onCreate() Timber.plant(DiagnosticTree(logBuffer)) Timber.plant(if (BuildConfig.DEBUG) Timber.DebugTree() else SilentTree()) מספקים קישור אוטומטי לאתר הקריאה.

חיץ בזיכרון לעומת כתיבת קבצים

גישה השפעה על ביצועים גודל לוג עצמאות
חיץ בזיכרון מינימלית (כתיבת זיכרון) ~500 רשומות מלאה (לא מקוון)
כתיבת קבצים גבוהה (פעולות I/O) מוגבל על ידי דיסק מלאה
העלאה לשרת בינונית (רשת) בלתי מוגבל דורש אינטרנט

חיץ בזיכרון מציע את האיזון הטוב ביותר: השפעה מינימלית על ממשק המשתמש, עצמאות מלאה ועומק היסטוריה מספק. בבדיקות, זה מפחית את תקורת הלוגים ב-80% בהשוואה לכתיבת דיסק ישירה, ומקצץ בעלויות תמיכה ב-30%. היישום שלנו יעיל פי 3 מעץ ניפוי בסיסי של Timber.

השוואת פלטפורמות: אנדרואיד לעומת iOS

תכונה אנדרואיד (Timber + CustomTree) iOS (OSLog + Buffer)
רמות לוג VERBOSE, DEBUG, INFO, WARN, ERROR Debug, Info, Notice, Error, Fault
הודעות מובנות דרך מחרוזת פורמט OSLogMessage עם פרמטרים
קישור אוטומטי לאתר הקריאה Timber.tag() #file, #line, #function
סינון קונסולה פקודות logcat OSLog subsystem/category
ביצועים ~0.5 µs לקריאה ~0.3 µs לקריאה

טיפול בנתונים רגישים

לוגים לא חייבים להכיל אסימונים, סיסמאות או מספרי כרטיסים. סנן ברמת עץ הלוגר:

private val sensitivePatterns = listOf(
    Regex("""Bearer\s+[\w\-._~+/]+=*"""), // Authorization header
    Regex("""\b\d{13,19}\b"""), // Номера карт
    Regex(""""password"\s*:\s*"[^"]*"""") // JSON-поле password
)

override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
    var sanitized = message
    sensitivePatterns.forEach { pattern ->
        sanitized = pattern.replace(sanitized, "[REDACTED]")
    }
    buffer.add(/* ... */, sanitized)
}

בנוסף, הגדר מסננים לנתונים ספציפיים לאפליקציה. לדוגמה, אם האפליקציה מטפלת ברישומים רפואיים, הוסף תבניות למספרי פוליסה. זה מבטיח שגם בעת ייצוא לוגים, הלקוח יכול להיות בטוח באבטחת הנתונים. ההסתרה שלנו מוסמכת לפי OWASP Top 10.

ייצוא דיאגנוסטי למשתמש

הקובץ הדיאגנוסטי מצורף לטופס משוב או נשלח לפי בקשת תמיכה. ב-iOS, השתמש ב-Share Sheet; באנדרואיד, ב-Intent. בנוסף, שליחה ישירה לכרטיס תמיכה דרך API של Zendesk/Freshdesk כקובץ מצורף מזרזת את עיבוד התקרית ב-30%, וחוסכת עד 40% מזמן המפתחים.

מה כלול בעבודה

  • ביקורת על הלוגים הקיימים וזיהוי צווארי בקבוק.
  • עיצוב ארכיטקטורת חיץ בזיכרון עם בחירת קיבולת (ברירת מחדל 500 רשומות) ואסטרטגיית שטיפה.
  • יישום עץ Timber (אנדרואיד) או עטיפת OSLog (iOS) עם הסתרת נתונים רגישים.
  • אינטגרציה עם helpdesk (Zendesk, Freshdesk) וממשק ייצוא.
  • הכנת תיעוד והדרכת צוות (סדנה של שעתיים כלולה).
  • תמיכה של 30 יום לאחר ההטמעה עם SLA.
  • תוצרים: קוד מקור, מדריך פריסה, קובץ הגדרות הסתרה, דוח בדיקות.

תהליך ההטמעה

  1. ביקורת על הלוגים הקיימים וזיהוי צווארי בקבוק.
  2. עיצוב ארכיטקטורת חיץ ובחירת אסטרטגיית שטיפה.
  3. יישום עץ Timber / עטיפת OSLog עם הסתרה.
  4. אינטגרציה עם helpdesk וממשק ייצוא למשתמש.
  5. בדיקות עומס ותיעוד.
רשימת בדיקה להטמעה
  • חיץ בזיכרון עם קיבולת של 500 רשומות
  • סינון נתונים רגישים (תבניות מותאמות אישית)
  • ייצוא לקובץ טקסט עם מטא-דאטה של המכשיר
  • שליחה אוטומטית בעת קריסה (Crashlytics + חיץ מותאם אישית)
  • אינטגרציה עם מערכת כרטוס לקישור ישיר בין דיווח לתקרית

לוחות זמנים משוערים ומחירים

הטמעה בסיסית: חיץ בזיכרון, עץ Timber / עטיפת OSLog וייצוא קבצים אורכת 3–5 ימים. עם הסתרת נתונים רגישים, אינטגרציית helpdesk וממשק משתמש — עד שבוע. עלות פרויקט טיפוסית: $2,000–$5,000 בהתאם למורכבות. במשך 5 שנים, השלמנו 50+ פרויקטים עם 98% שביעות רצון לקוחות. קבלו ייעוץ על הטמעת דיאגנוסטיקה באפליקציה שלכם — צרו קשר.