<commit_before>//
//  LogHTTPService.swift
//  ZamzamCore
//
//  Created by <NAME> on 2020-03-04.
//  Copyright © 2020 Zamzam Inc. All rights reserved.
//

#if os(iOS)
import Foundation
import UIKit.UIApplication
import UIKit.UIDevice
import AdSupport

/// Log destination for sending over HTTP.
final public class LogHTTPService {
    private let urlRequest: URLRequest
    private let maxEntriesInBuffer: Int
    private let appInfo: AppInfo
    private let networkRepository: NetworkRepositoryType
    
    private let deviceName = UIDevice.current.name
    private let deviceModel = UIDevice.current.model
    private var deviceIdentifier = UIDevice.current.identifierForVendor?.uuidString ?? ""
    private var advertisingIdentifier = ASIdentifierManager.shared().advertisingIdentifier.uuidString
    private let osVersion = UIDevice.current.systemVersion
    
    /// Stores the log entries in memory until it is ready to send.
    private var buffer: [String] = [] {
        didSet { buffer.count > maxEntriesInBuffer ? send() : nil }
    }
    
    /// The initializer of the log destination.
    ///
    /// - Parameters:
    ///   - urlRequest: A URL load request for the destination. Leave data `nil` as this will be added to the `httpBody` upon sending.
    ///   - maxEntriesInBuffer: The threshold of the buffer before sending to the destination.
    ///   - appInfo: Provides details of the current app.
    ///   - networkRepository: The object used to send the HTTP request.
    ///   - notificationCenter: A notification dispatch mechanism that registers observers for flushing the buffer at certain app lifecycle events.
    public init(
        urlRequest: URLRequest,
        maxEntriesInBuffer: Int,
        appInfo: AppInfo,
        networkRepository: NetworkRepositoryType,
        notificationCenter: NotificationCenter
    ) {
        self.urlRequest = urlRequest
        self.maxEntriesInBuffer = maxEntriesInBuffer
        self.appInfo = appInfo
        self.networkRepository = networkRepository
        
        notificationCenter.addObserver(
            self,
            selector: #selector(send),
            name: UIApplication.willResignActiveNotification,
            object: nil
        )
        
        notificationCenter.addObserver(
            self,
            selector: #selector(send),
            name: UIApplication.willTerminateNotification,
            object: nil
        )
    }
}

public extension LogHTTPService {
    
    /// Appends the log to the buffer that will be queued for later sending.
    ///
    /// The buffer size is determined in the initializer. Once the threshold is met,
    /// the entries will be flushed and sent to the destination. The buffer is
    /// also automatically flushed on the `willResignActive` and
    /// `willTerminate` events.
    ///
    /// - Parameters:
    ///   - parameters: The values that will be merged and sent to the detination.
    ///   - level: The current level of the log entry.
    ///   - path: Path of the caller.
    ///   - function: Function of the caller.
    ///   - line: Line of the caller.
    func write(
        _ parameters: [String: Any],
        level: LogAPI.Level,
        path: String,
        function: String,
        line: Int
    ) {
        let session: [String: Any] = [
            "app": [
                "name": appInfo.appDisplayName ?? "Unknown",
                "version": appInfo.appVersion ?? "Unknown",
                "build": appInfo.appBuild ?? "Unknown",
                "bundle_id": appInfo.appBundleID ?? "Unknown"
            ],
            "device": [
                "device_id": deviceIdentifier,
                "advertising_id": advertisingIdentifier,
                "device_name": deviceName,
                "device_model": deviceModel,
                "os_version": osVersion,
                "is_testflight": appInfo.isInTestFlight,
                "is_simulator": appInfo.isRunningOnSimulator
            ],
            "code": [
                "path": path,
                "function": function,
                "line": line
            ]
        ]
        
        let merged = parameters.merging(session) { (parameter, _) in parameter }
        
        guard let log = merged.jsonString() else {
            print("ERROR: Logger unable to serialize parameters for destination.")
            return
        }
        
        // Store in buffer for sending later
        buffer.append(log)
    }
}

private extension LogHTTPService {
    
    @objc func send() {
        let logs = buffer
        buffer = []
        
        guard let data = logs.joined(separator: "\n").data(using: .utf8) else {
            debugPrint("Could not begin log destination task")
            return
        }
        
        var request = urlRequest
        request.httpBody = data
        
        BackgroundTask.run(for: .shared) { task in
            self.networkRepository.send(with: request) {
                if case .failure(let error) = $0 {
                    debugPrint("Error from log destination: \(error)")
                }
                
                task.end()
            }
        }
    }
}
#endif
<commit_msg>Remove advertising identifier for App Store<commit_after>//
//  LogHTTPService.swift
//  ZamzamCore
//
//  Created by <NAME> on 2020-03-04.
//  Copyright © 2020 Zamzam Inc. All rights reserved.
//

#if os(iOS)
import Foundation
import UIKit.UIApplication
import UIKit.UIDevice

/// Log destination for sending over HTTP.
final public class LogHTTPService {
    private let urlRequest: URLRequest
    private let maxEntriesInBuffer: Int
    private let appInfo: AppInfo
    private let networkRepository: NetworkRepositoryType
    
    private let deviceName = UIDevice.current.name
    private let deviceModel = UIDevice.current.model
    private var deviceIdentifier = UIDevice.current.identifierForVendor?.uuidString ?? ""
    private let osVersion = UIDevice.current.systemVersion
    
    /// Stores the log entries in memory until it is ready to send.
    private var buffer: [String] = [] {
        didSet { buffer.count > maxEntriesInBuffer ? send() : nil }
    }
    
    /// The initializer of the log destination.
    ///
    /// - Parameters:
    ///   - urlRequest: A URL load request for the destination. Leave data `nil` as this will be added to the `httpBody` upon sending.
    ///   - maxEntriesInBuffer: The threshold of the buffer before sending to the destination.
    ///   - appInfo: Provides details of the current app.
    ///   - networkRepository: The object used to send the HTTP request.
    ///   - notificationCenter: A notification dispatch mechanism that registers observers for flushing the buffer at certain app lifecycle events.
    public init(
        urlRequest: URLRequest,
        maxEntriesInBuffer: Int,
        appInfo: AppInfo,
        networkRepository: NetworkRepositoryType,
        notificationCenter: NotificationCenter
    ) {
        self.urlRequest = urlRequest
        self.maxEntriesInBuffer = maxEntriesInBuffer
        self.appInfo = appInfo
        self.networkRepository = networkRepository
        
        notificationCenter.addObserver(
            self,
            selector: #selector(send),
            name: UIApplication.willResignActiveNotification,
            object: nil
        )
        
        notificationCenter.addObserver(
            self,
            selector: #selector(send),
            name: UIApplication.willTerminateNotification,
            object: nil
        )
    }
}

public extension LogHTTPService {
    
    /// Appends the log to the buffer that will be queued for later sending.
    ///
    /// The buffer size is determined in the initializer. Once the threshold is met,
    /// the entries will be flushed and sent to the destination. The buffer is
    /// also automatically flushed on the `willResignActive` and
    /// `willTerminate` events.
    ///
    /// - Parameters:
    ///   - parameters: The values that will be merged and sent to the detination.
    ///   - level: The current level of the log entry.
    ///   - path: Path of the caller.
    ///   - function: Function of the caller.
    ///   - line: Line of the caller.
    func write(
        _ parameters: [String: Any],
        level: LogAPI.Level,
        path: String,
        function: String,
        line: Int
    ) {
        let session: [String: Any] = [
            "app": [
                "name": appInfo.appDisplayName ?? "Unknown",
                "version": appInfo.appVersion ?? "Unknown",
                "build": appInfo.appBuild ?? "Unknown",
                "bundle_id": appInfo.appBundleID ?? "Unknown"
            ],
            "device": [
                "device_id": deviceIdentifier,
                "device_name": deviceName,
                "device_model": deviceModel,
                "os_version": osVersion,
                "is_testflight": appInfo.isInTestFlight,
                "is_simulator": appInfo.isRunningOnSimulator
            ],
            "code": [
                "path": path,
                "function": function,
                "line": line
            ]
        ]
        
        let merged = parameters.merging(session) { (parameter, _) in parameter }
        
        guard let log = merged.jsonString() else {
            print("ERROR: Logger unable to serialize parameters for destination.")
            return
        }
        
        // Store in buffer for sending later
        buffer.append(log)
    }
}

private extension LogHTTPService {
    
    @objc func send() {
        let logs = buffer
        buffer = []
        
        guard let data = logs.joined(separator: "\n").data(using: .utf8) else {
            debugPrint("Could not begin log destination task")
            return
        }
        
        var request = urlRequest
        request.httpBody = data
        
        BackgroundTask.run(for: .shared) { task in
            self.networkRepository.send(with: request) {
                if case .failure(let error) = $0 {
                    debugPrint("Error from log destination: \(error)")
                }
                
                task.end()
            }
        }
    }
}
#endif

{'fraction_non_alphanumeric': 0.08788412605206498, 'fraction_numerical': 0.002740262282247015, 'mean_word_length': 1.8512834821428572, 'pattern_counts': {'":': 33, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4820193', 'n_tokens_mistral': 2633, 'n_tokens_neox': 2563, 'n_words': 825}