diff --git a/app/build.gradle b/app/build.gradle index decdc202..b3253cdd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -75,13 +75,15 @@ dependencies { implementation 'androidx.preference:preference-ktx:1.2.0' implementation 'com.github.cyb3rko:QuickPermissions-Kotlin:1.1.2' - implementation 'com.hypertrack:hyperlog:0.0.10' implementation 'com.squareup.picasso:picasso:2.71828' implementation 'io.noties.markwon:core:4.6.2' implementation 'io.noties.markwon:image-picasso:4.6.2' implementation 'io.noties.markwon:image:4.6.2' implementation 'io.noties.markwon:ext-tables:4.6.2' implementation 'io.noties.markwon:ext-strikethrough:4.6.2' + + implementation 'org.tinylog:tinylog-api-kotlin:2.6.2' + implementation 'org.tinylog:tinylog-impl:2.6.2' } configurations { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6cbd775e..ff4af56d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,7 @@ = Build.VERSION_CODES.O) { + NotificationSupport.createForegroundChannel( + this, + this.getSystemService(NotificationManager::class.java) + ) + } + + super.onCreate() + } +} diff --git a/app/src/main/kotlin/com/github/gotify/MissedMessageUtil.kt b/app/src/main/kotlin/com/github/gotify/MissedMessageUtil.kt index 3a697593..52e1a0f6 100644 --- a/app/src/main/kotlin/com/github/gotify/MissedMessageUtil.kt +++ b/app/src/main/kotlin/com/github/gotify/MissedMessageUtil.kt @@ -5,7 +5,7 @@ import com.github.gotify.api.ApiException import com.github.gotify.api.Callback import com.github.gotify.client.api.MessageApi import com.github.gotify.client.model.Message -import com.github.gotify.log.Log +import org.tinylog.kotlin.Logger internal class MissedMessageUtil(private val api: MessageApi) { fun lastReceivedMessage(acceptID: (Long) -> Unit) { @@ -41,7 +41,7 @@ internal class MissedMessageUtil(private val api: MessageApi) { since = pagedMessages.paging.since } } catch (e: ApiException) { - Log.e("cannot retrieve missing messages", e) + Logger.error(e, "cannot retrieve missing messages") } return result.reversed() } diff --git a/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt b/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt index dd27c224..c9f5800c 100644 --- a/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt +++ b/app/src/main/kotlin/com/github/gotify/NotificationSupport.kt @@ -10,7 +10,7 @@ import android.os.Build import androidx.annotation.RequiresApi import androidx.preference.PreferenceManager import com.github.gotify.client.model.Application -import com.github.gotify.log.Log +import org.tinylog.kotlin.Logger internal object NotificationSupport { @RequiresApi(Build.VERSION_CODES.O) @@ -93,7 +93,7 @@ internal object NotificationSupport { notificationManager.createNotificationChannel(messagesImportanceDefault) notificationManager.createNotificationChannel(messagesImportanceHigh) } catch (e: Exception) { - Log.e("Could not create channel", e) + Logger.error(e, "Could not create channel") } } @@ -168,7 +168,7 @@ internal object NotificationSupport { notificationManager.createNotificationChannel(messagesImportanceDefault) notificationManager.createNotificationChannel(messagesImportanceHigh) } catch (e: Exception) { - Log.e("Could not create channel", e) + Logger.error(e, "Could not create channel") } } diff --git a/app/src/main/kotlin/com/github/gotify/Utils.kt b/app/src/main/kotlin/com/github/gotify/Utils.kt index 772d562a..196d0481 100644 --- a/app/src/main/kotlin/com/github/gotify/Utils.kt +++ b/app/src/main/kotlin/com/github/gotify/Utils.kt @@ -12,7 +12,6 @@ import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import com.github.gotify.client.JSON -import com.github.gotify.log.Log import com.google.android.material.snackbar.Snackbar import com.google.gson.Gson import com.squareup.picasso.Picasso.LoadedFrom @@ -31,6 +30,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import okio.Buffer import org.threeten.bp.OffsetDateTime +import org.tinylog.kotlin.Logger internal object Utils { val JSON: Gson = JSON().gson @@ -63,10 +63,10 @@ internal object Utils { URL(URL(baseURL), target).toString() } } catch (e: MalformedURLException) { - Log.e("Could not resolve absolute url", e) + Logger.error(e, "Could not resolve absolute url") target } catch (e: URISyntaxException) { - Log.e("Could not resolve absolute url", e) + Logger.error(e, "Could not resolve absolute url") target } } @@ -79,7 +79,7 @@ internal object Utils { } override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) { - Log.e("Bitmap failed", e) + Logger.error(e, "Bitmap failed") } override fun onPrepareLoad(placeHolderDrawable: Drawable) {} diff --git a/app/src/main/kotlin/com/github/gotify/api/Callback.kt b/app/src/main/kotlin/com/github/gotify/api/Callback.kt index 0ef273cd..5b0d0f1e 100644 --- a/app/src/main/kotlin/com/github/gotify/api/Callback.kt +++ b/app/src/main/kotlin/com/github/gotify/api/Callback.kt @@ -1,7 +1,9 @@ package com.github.gotify.api import android.app.Activity -import com.github.gotify.log.Log +import com.github.gotify.api.Callback.ErrorCallback +import com.github.gotify.api.Callback.SuccessCallback +import org.tinylog.kotlin.Logger import retrofit2.Call import retrofit2.Response @@ -65,7 +67,7 @@ internal class Callback private constructor( private fun errorCallback(): Callback { return Callback( onSuccess = {}, - onError = { exception -> Log.e("Error while api call", exception) } + onError = { exception -> Logger.error(exception, "Error while api call") } ) } diff --git a/app/src/main/kotlin/com/github/gotify/api/CertUtils.kt b/app/src/main/kotlin/com/github/gotify/api/CertUtils.kt index 60a295bf..ce0cb26c 100644 --- a/app/src/main/kotlin/com/github/gotify/api/CertUtils.kt +++ b/app/src/main/kotlin/com/github/gotify/api/CertUtils.kt @@ -3,7 +3,6 @@ package com.github.gotify.api import android.annotation.SuppressLint import com.github.gotify.SSLSettings import com.github.gotify.Utils -import com.github.gotify.log.Log import java.io.IOException import java.security.GeneralSecurityException import java.security.KeyStore @@ -16,15 +15,18 @@ import javax.net.ssl.TrustManager import javax.net.ssl.TrustManagerFactory import javax.net.ssl.X509TrustManager import okhttp3.OkHttpClient +import org.tinylog.kotlin.Logger internal object CertUtils { @SuppressLint("CustomX509TrustManager") private val trustAll = object : X509TrustManager { @SuppressLint("TrustAllX509TrustManager") - override fun checkClientTrusted(chain: Array, authType: String) {} + override fun checkClientTrusted(chain: Array, authType: String) { + } @SuppressLint("TrustAllX509TrustManager") - override fun checkServerTrusted(chain: Array, authType: String) {} + override fun checkServerTrusted(chain: Array, authType: String) { + } override fun getAcceptedIssuers() = arrayOf() } @@ -62,7 +64,7 @@ internal object CertUtils { } } catch (e: Exception) { // We shouldn't have issues since the cert is verified on login. - Log.e("Failed to apply SSL settings", e) + Logger.error(e, "Failed to apply SSL settings") } } diff --git a/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt b/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt index fc9e7433..474c3af9 100644 --- a/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/init/InitializationActivity.kt @@ -2,8 +2,6 @@ package com.github.gotify.init import android.Manifest import android.app.AlarmManager -import android.app.NotificationManager -import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build @@ -13,8 +11,6 @@ import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.preference.PreferenceManager -import com.github.gotify.NotificationSupport import com.github.gotify.R import com.github.gotify.Settings import com.github.gotify.api.ApiException @@ -23,16 +19,14 @@ import com.github.gotify.api.Callback.SuccessCallback import com.github.gotify.api.ClientFactory import com.github.gotify.client.model.User import com.github.gotify.client.model.VersionInfo -import com.github.gotify.log.Log -import com.github.gotify.log.UncaughtExceptionHandler import com.github.gotify.login.LoginActivity import com.github.gotify.messages.MessagesActivity import com.github.gotify.service.WebSocketService -import com.github.gotify.settings.ThemeHelper import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.livinglifetechway.quickpermissionskotlin.runWithPermissions import com.livinglifetechway.quickpermissionskotlin.util.QuickPermissionsOptions import com.livinglifetechway.quickpermissionskotlin.util.QuickPermissionsRequest +import org.tinylog.kotlin.Logger internal class InitializationActivity : AppCompatActivity() { @@ -47,20 +41,8 @@ internal class InitializationActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - Log.init(this) - val theme = PreferenceManager.getDefaultSharedPreferences(this) - .getString(getString(R.string.setting_key_theme), getString(R.string.theme_default))!! - ThemeHelper.setTheme(this, theme) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationSupport.createForegroundChannel( - this, - (this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager) - ) - } - UncaughtExceptionHandler.registerCurrentThread() settings = Settings(this) - Log.i("Entering ${javaClass.simpleName}") + Logger.info("Entering ${javaClass.simpleName}") installSplashScreen().setKeepOnScreenCondition { splashScreenActive } @@ -115,6 +97,7 @@ internal class InitializationActivity : AppCompatActivity() { dialog(getString(R.string.not_available, settings.url)) return } + 401 -> { dialog(getString(R.string.auth_failed)) return @@ -153,7 +136,7 @@ internal class InitializationActivity : AppCompatActivity() { } private fun authenticated(user: User) { - Log.i("Authenticated as ${user.name}") + Logger.info("Authenticated as ${user.name}") settings.setUser(user.name, user.isAdmin) requestVersion { @@ -172,7 +155,7 @@ internal class InitializationActivity : AppCompatActivity() { private fun requestVersion(runnable: Runnable) { requestVersion( callback = Callback.SuccessBody { version: VersionInfo -> - Log.i("Server version: ${version.version}@${version.buildDate}") + Logger.info("Server version: ${version.version}@${version.buildDate}") settings.serverVersion = version.version runnable.run() }, diff --git a/app/src/main/kotlin/com/github/gotify/log/Format.kt b/app/src/main/kotlin/com/github/gotify/log/Format.kt deleted file mode 100644 index 578d2319..00000000 --- a/app/src/main/kotlin/com/github/gotify/log/Format.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.github.gotify.log - -import android.content.Context -import com.hypertrack.hyperlog.LogFormat - -internal class Format(context: Context) : LogFormat(context) { - override fun getFormattedLogMessage( - logLevelName: String, - tag: String, - message: String, - timeStamp: String, - senderName: String, - osVersion: String, - deviceUuid: String - ) = "$timeStamp $logLevelName: $message" -} diff --git a/app/src/main/kotlin/com/github/gotify/log/Log.kt b/app/src/main/kotlin/com/github/gotify/log/Log.kt deleted file mode 100644 index a4f3b912..00000000 --- a/app/src/main/kotlin/com/github/gotify/log/Log.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.github.gotify.log - -import android.content.Context -import android.util.Log -import com.hypertrack.hyperlog.HyperLog - -internal object Log { - private const val TAG = "gotify" - - fun init(content: Context) { - HyperLog.initialize(content, Format(content)) - HyperLog.setLogLevel(Log.INFO) // TODO configurable - } - - fun get(): String { - val logs = HyperLog.getDeviceLogsAsStringList(false) - return logs.takeLast(200).reversed().joinToString("\n") - } - - fun e(message: String) { - HyperLog.e(TAG, message) - } - - fun e(message: String, e: Throwable) { - HyperLog.e(TAG, "$message\n${Log.getStackTraceString(e)}") - } - - fun i(message: String) { - HyperLog.i(TAG, message) - } - - fun i(message: String, e: Throwable) { - HyperLog.i(TAG, "$message\n${Log.getStackTraceString(e)}") - } - - fun w(message: String) { - HyperLog.w(TAG, message) - } - - fun w(message: String, e: Throwable) { - HyperLog.w(TAG, "$message\n${Log.getStackTraceString(e)}") - } - - fun clear() { - HyperLog.deleteLogs() - } -} diff --git a/app/src/main/kotlin/com/github/gotify/log/LoggerHelper.kt b/app/src/main/kotlin/com/github/gotify/log/LoggerHelper.kt new file mode 100644 index 00000000..cee7cca1 --- /dev/null +++ b/app/src/main/kotlin/com/github/gotify/log/LoggerHelper.kt @@ -0,0 +1,43 @@ +package com.github.gotify.log + +import android.content.Context +import java.io.File +import org.tinylog.kotlin.Logger + +class LoggerHelper { + companion object { + fun read(ctx: Context): String = folder(ctx) + .listFiles() + .orEmpty() + .flatMap { it.readLines() } + .fold(mutableListOf()) { newLines, line -> groupExceptions(newLines, line) } + .takeLast(200) + .reversed() + .joinToString(separator = "\n") + + private fun groupExceptions( + newLines: MutableList, + line: String + ): MutableList { + if (newLines.isNotEmpty() && (line.startsWith('\t') || line.startsWith("Caused"))) { + newLines[newLines.lastIndex] += '\n' + line + } else { + newLines.add(line) + } + return newLines + } + + fun clear(ctx: Context) { + folder(ctx).listFiles()?.forEach { it.writeText("") } + Logger.info("Logs cleared") + } + + fun init(ctx: Context) { + val file = folder(ctx) + file.mkdirs() + System.setProperty("tinylog.directory", file.absolutePath) + } + + private fun folder(ctx: Context): File = File(ctx.filesDir, "log") + } +} diff --git a/app/src/main/kotlin/com/github/gotify/log/LogsActivity.kt b/app/src/main/kotlin/com/github/gotify/log/LogsActivity.kt index d78dbc41..4fc06102 100644 --- a/app/src/main/kotlin/com/github/gotify/log/LogsActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/log/LogsActivity.kt @@ -15,6 +15,7 @@ import com.github.gotify.Utils.launchCoroutine import com.github.gotify.databinding.ActivityLogsBinding import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import org.tinylog.kotlin.Logger internal class LogsActivity : AppCompatActivity() { @@ -25,7 +26,7 @@ internal class LogsActivity : AppCompatActivity() { super.onCreate(savedInstanceState) binding = ActivityLogsBinding.inflate(layoutInflater) setContentView(binding.root) - Log.i("Entering ${javaClass.simpleName}") + Logger.info("Entering ${javaClass.simpleName}") updateLogs() setSupportActionBar(binding.appBarDrawer.toolbar) val actionBar = supportActionBar @@ -37,7 +38,7 @@ internal class LogsActivity : AppCompatActivity() { private fun updateLogs() { launchCoroutine { - val log = Log.get() + val log = LoggerHelper.read(this) withContext(Dispatchers.Main) { val content = binding.logContent if (content.selectionStart == content.selectionEnd) { @@ -62,11 +63,13 @@ internal class LogsActivity : AppCompatActivity() { finish() true } + R.id.action_delete_logs -> { - Log.clear() + LoggerHelper.clear(this) binding.logContent.text = null true } + R.id.action_copy_logs -> { val content = binding.logContent val clipboardManager = @@ -76,6 +79,7 @@ internal class LogsActivity : AppCompatActivity() { Utils.showSnackBar(this, getString(R.string.logs_copied)) true } + else -> false } } diff --git a/app/src/main/kotlin/com/github/gotify/log/UncaughtExceptionHandler.kt b/app/src/main/kotlin/com/github/gotify/log/UncaughtExceptionHandler.kt index 024af8ab..92aebcad 100644 --- a/app/src/main/kotlin/com/github/gotify/log/UncaughtExceptionHandler.kt +++ b/app/src/main/kotlin/com/github/gotify/log/UncaughtExceptionHandler.kt @@ -1,11 +1,11 @@ package com.github.gotify.log -import com.github.gotify.log.Log.e +import org.tinylog.kotlin.Logger internal object UncaughtExceptionHandler { fun registerCurrentThread() { - Thread.setDefaultUncaughtExceptionHandler { _, e: Throwable? -> - e("uncaught exception", e!!) + Thread.setDefaultUncaughtExceptionHandler { _, e: Throwable -> + Logger.error(e, "uncaught exception") } } } diff --git a/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt b/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt index 77305c73..1f2d31ef 100644 --- a/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/login/LoginActivity.kt @@ -27,13 +27,13 @@ import com.github.gotify.client.model.VersionInfo import com.github.gotify.databinding.ActivityLoginBinding import com.github.gotify.databinding.ClientNameDialogBinding import com.github.gotify.init.InitializationActivity -import com.github.gotify.log.Log import com.github.gotify.log.LogsActivity import com.github.gotify.log.UncaughtExceptionHandler import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.textfield.TextInputEditText import java.security.cert.X509Certificate import okhttp3.HttpUrl +import org.tinylog.kotlin.Logger internal class LoginActivity : AppCompatActivity() { private lateinit var binding: ActivityLoginBinding @@ -69,7 +69,7 @@ internal class LoginActivity : AppCompatActivity() { UncaughtExceptionHandler.registerCurrentThread() binding = ActivityLoginBinding.inflate(layoutInflater) setContentView(binding.root) - Log.i("Entering ${javaClass.simpleName}") + Logger.info("Entering ${javaClass.simpleName}") settings = Settings(this) } diff --git a/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt b/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt index ac49dd66..929fa708 100644 --- a/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/messages/MessagesActivity.kt @@ -45,7 +45,6 @@ import com.github.gotify.client.model.Client import com.github.gotify.client.model.Message import com.github.gotify.databinding.ActivityMessagesBinding import com.github.gotify.init.InitializationActivity -import com.github.gotify.log.Log import com.github.gotify.log.LogsActivity import com.github.gotify.login.LoginActivity import com.github.gotify.messages.provider.MessageState @@ -60,6 +59,7 @@ import com.google.android.material.snackbar.Snackbar import java.io.IOException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import org.tinylog.kotlin.Logger internal class MessagesActivity : AppCompatActivity(), @@ -89,7 +89,7 @@ internal class MessagesActivity : binding = ActivityMessagesBinding.inflate(layoutInflater) setContentView(binding.root) viewModel = ViewModelProvider(this, MessagesModelFactory(this))[MessagesModel::class.java] - Log.i("Entering " + javaClass.simpleName) + Logger.info("Entering " + javaClass.simpleName) initDrawer() val layoutManager = LinearLayoutManager(this) @@ -132,6 +132,7 @@ internal class MessagesActivity : override fun onDrawerOpened(drawerView: View) { onBackPressedCallback.isEnabled = true } + override fun onDrawerClosed(drawerView: View) { updateAppOnDrawerClose?.let { selectApp -> updateAppOnDrawerClose = null @@ -175,7 +176,7 @@ internal class MessagesActivity : try { viewModel.picassoHandler.evict() } catch (e: IOException) { - Log.e("Problem evicting Picasso cache", e) + Logger.error(e, "Problem evicting Picasso cache") } startActivity(Intent(this, InitializationActivity::class.java)) finish() @@ -625,13 +626,13 @@ internal class MessagesActivity : } } if (currentClient != null) { - Log.i("Delete client with id " + currentClient.id) + Logger.info("Delete client with id " + currentClient.id) Api.execute(api.deleteClient(currentClient.id)) } else { - Log.e("Could not delete client, client does not exist.") + Logger.error("Could not delete client, client does not exist.") } } catch (e: ApiException) { - Log.e("Could not delete client", e) + Logger.error(e, "Could not delete client") } viewModel.settings.clear() diff --git a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt index 973ea1fc..d2eb3f28 100644 --- a/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt +++ b/app/src/main/kotlin/com/github/gotify/messages/provider/MessageRequester.kt @@ -6,31 +6,31 @@ import com.github.gotify.api.Callback import com.github.gotify.client.api.MessageApi import com.github.gotify.client.model.Message import com.github.gotify.client.model.PagedMessages -import com.github.gotify.log.Log +import org.tinylog.kotlin.Logger internal class MessageRequester(private val messageApi: MessageApi) { fun loadMore(state: MessageState): PagedMessages? { return try { - Log.i("Loading more messages for ${state.appId}") + Logger.info("Loading more messages for ${state.appId}") if (MessageState.ALL_MESSAGES == state.appId) { Api.execute(messageApi.getMessages(LIMIT, state.nextSince)) } else { Api.execute(messageApi.getAppMessages(state.appId, LIMIT, state.nextSince)) } } catch (apiException: ApiException) { - Log.e("failed requesting messages", apiException) + Logger.error(apiException, "failed requesting messages") null } } fun asyncRemoveMessage(message: Message) { - Log.i("Removing message with id ${message.id}") + Logger.info("Removing message with id ${message.id}") messageApi.deleteMessage(message.id).enqueue(Callback.call()) } fun deleteAll(appId: Long): Boolean { return try { - Log.i("Deleting all messages for $appId") + Logger.info("Deleting all messages for $appId") if (MessageState.ALL_MESSAGES == appId) { Api.execute(messageApi.deleteMessages()) } else { @@ -38,7 +38,7 @@ internal class MessageRequester(private val messageApi: MessageApi) { } true } catch (e: ApiException) { - Log.e("Could not delete messages", e) + Logger.error(e, "Could not delete messages") false } } diff --git a/app/src/main/kotlin/com/github/gotify/picasso/PicassoDataRequestHandler.kt b/app/src/main/kotlin/com/github/gotify/picasso/PicassoDataRequestHandler.kt index 14f00528..091fb6f8 100644 --- a/app/src/main/kotlin/com/github/gotify/picasso/PicassoDataRequestHandler.kt +++ b/app/src/main/kotlin/com/github/gotify/picasso/PicassoDataRequestHandler.kt @@ -2,10 +2,10 @@ package com.github.gotify.picasso import android.graphics.BitmapFactory import android.util.Base64 -import com.github.gotify.log.Log import com.squareup.picasso.Picasso import com.squareup.picasso.Request import com.squareup.picasso.RequestHandler +import org.tinylog.kotlin.Logger /** * Adapted from https://github.com/square/picasso/issues/1395#issuecomment-220929377 By @@ -30,7 +30,7 @@ internal class PicassoDataRequestHandler : RequestHandler() { if (bitmap == null) { val show = if (uri.length > 50) uri.take(50) + "..." else uri val malformed = RuntimeException("Malformed data uri: $show") - Log.e("Could not load image", malformed) + Logger.error(malformed, "Could not load image") throw malformed } diff --git a/app/src/main/kotlin/com/github/gotify/picasso/PicassoHandler.kt b/app/src/main/kotlin/com/github/gotify/picasso/PicassoHandler.kt index 1a80bdb4..0189d6aa 100644 --- a/app/src/main/kotlin/com/github/gotify/picasso/PicassoHandler.kt +++ b/app/src/main/kotlin/com/github/gotify/picasso/PicassoHandler.kt @@ -8,13 +8,13 @@ import com.github.gotify.Settings import com.github.gotify.Utils import com.github.gotify.api.CertUtils import com.github.gotify.client.model.Application -import com.github.gotify.log.Log import com.squareup.picasso.OkHttp3Downloader import com.squareup.picasso.Picasso import java.io.File import java.io.IOException import okhttp3.Cache import okhttp3.OkHttpClient +import org.tinylog.kotlin.Logger internal class PicassoHandler(private val context: Context, private val settings: Settings) { companion object { @@ -52,7 +52,7 @@ internal class PicassoHandler(private val context: Context, private val settings Utils.resolveAbsoluteUrl("${settings.url}/", app.image) ) } catch (e: IOException) { - Log.e("Could not load image for notification", e) + Logger.error(e, "Could not load image for notification") } return BitmapFactory.decodeResource(context.resources, R.drawable.gotify) } diff --git a/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt b/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt index a92922bf..6b149840 100644 --- a/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt +++ b/app/src/main/kotlin/com/github/gotify/service/WebSocketConnection.kt @@ -8,7 +8,6 @@ import com.github.gotify.SSLSettings import com.github.gotify.Utils import com.github.gotify.api.CertUtils import com.github.gotify.client.model.Message -import com.github.gotify.log.Log import java.util.Calendar import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong @@ -18,6 +17,7 @@ import okhttp3.Request import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener +import org.tinylog.kotlin.Logger internal class WebSocketConnection( private val baseUrl: String, @@ -105,7 +105,7 @@ internal class WebSocketConnection( close() state = State.Connecting val nextId = ID.incrementAndGet() - Log.i("WebSocket($nextId): starting...") + Logger.info("WebSocket($nextId): starting...") webSocket = client.newWebSocket(request(), Listener(nextId)) return this @@ -116,7 +116,7 @@ internal class WebSocketConnection( if (webSocket != null) { webSocket?.close(1000, "") closed() - Log.i("WebSocket(${ID.get()}): closing existing connection.") + Logger.info("WebSocket(${ID.get()}): closing existing connection.") } } @@ -134,7 +134,7 @@ internal class WebSocketConnection( state = State.Scheduled if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - Log.i("WebSocket: scheduling a restart in $seconds second(s) (via alarm manager)") + Logger.info("WebSocket: scheduling a restart in $seconds second(s) (via alarm manager)") val future = Calendar.getInstance() future.add(Calendar.SECOND, seconds.toInt()) alarmManager.setExact( @@ -145,7 +145,7 @@ internal class WebSocketConnection( null ) } else { - Log.i("WebSocket: scheduling a restart in $seconds second(s)") + Logger.info("WebSocket: scheduling a restart in $seconds second(s)") reconnectHandler.removeCallbacks(reconnectCallback) reconnectHandler.postDelayed(reconnectCallback, TimeUnit.SECONDS.toMillis(seconds)) } @@ -155,7 +155,7 @@ internal class WebSocketConnection( override fun onOpen(webSocket: WebSocket, response: Response) { syncExec(id) { state = State.Connected - Log.i("WebSocket($id): opened") + Logger.info("WebSocket($id): opened") onOpen.run() if (errorCount > 0) { @@ -168,7 +168,7 @@ internal class WebSocketConnection( override fun onMessage(webSocket: WebSocket, text: String) { syncExec(id) { - Log.i("WebSocket($id): received message $text") + Logger.info("WebSocket($id): received message $text") val message = Utils.JSON.fromJson(text, Message::class.java) onMessageCallback(message) } @@ -178,7 +178,7 @@ internal class WebSocketConnection( override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { syncExec(id) { if (state == State.Connected) { - Log.w("WebSocket($id): closed") + Logger.warn("WebSocket($id): closed") onClose.run() } closed() @@ -189,7 +189,7 @@ internal class WebSocketConnection( override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { val code = if (response != null) "StatusCode: ${response.code()}" else "" val message = if (response != null) response.message() else "" - Log.e("WebSocket($id): failure $code Message: $message", t) + Logger.error(t) { "WebSocket($id): failure $code Message: $message" } syncExec(id) { closed() if (response != null && response.code() >= 400 && response.code() <= 499) { diff --git a/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt b/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt index 9b6d9813..8c0a5dbf 100644 --- a/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt +++ b/app/src/main/kotlin/com/github/gotify/service/WebSocketService.kt @@ -28,7 +28,7 @@ import com.github.gotify.client.api.ApplicationApi import com.github.gotify.client.api.MessageApi import com.github.gotify.client.model.Application import com.github.gotify.client.model.Message -import com.github.gotify.log.Log +import com.github.gotify.log.LoggerHelper import com.github.gotify.log.UncaughtExceptionHandler import com.github.gotify.messages.Extras import com.github.gotify.messages.IntentUrlDialogActivity @@ -37,6 +37,7 @@ import com.github.gotify.picasso.PicassoHandler import io.noties.markwon.Markwon import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong +import org.tinylog.kotlin.Logger internal class WebSocketService : Service() { companion object { @@ -50,7 +51,7 @@ internal class WebSocketService : Service() { object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { super.onAvailable(network) - Log.i("WebSocket: Network available, reconnect if needed.") + Logger.info("WebSocket: Network available, reconnect if needed.") connection?.start() } } @@ -71,7 +72,7 @@ internal class WebSocketService : Service() { settings.token ) missingMessageUtil = MissedMessageUtil(client.createService(MessageApi::class.java)) - Log.i("Create ${javaClass.simpleName}") + Logger.info("Create ${javaClass.simpleName}") picassoHandler = PicassoHandler(this, settings) markwon = MarkwonFactory.createForNotification(this, picassoHandler.get()) } @@ -84,15 +85,15 @@ internal class WebSocketService : Service() { .unregisterNetworkCallback(networkCallback) } - Log.w("Destroy ${javaClass.simpleName}") + Logger.warn("Destroy ${javaClass.simpleName}") } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Log.init(this) - if (connection != null) { - connection!!.close() - } - Log.i("Starting ${javaClass.simpleName}") + LoggerHelper.init(this) + UncaughtExceptionHandler.registerCurrentThread() + + connection?.close() + Logger.info("Starting ${javaClass.simpleName}") super.onStartCommand(intent, flags, startId) Thread { startPushService() }.start() @@ -168,7 +169,7 @@ internal class WebSocketService : Service() { getString(R.string.websocket_closed_logout) ) } else { - Log.i( + Logger.info( "WebSocket closed but the user still authenticated, " + "trying to reconnect" ) @@ -406,7 +407,7 @@ internal class WebSocketService : Service() { .bigPicture(picassoHandler.getImageFromUrl(notificationImageUrl)) ) } catch (e: Exception) { - Log.e("Error loading bigImageUrl", e) + Logger.error(e, "Error loading bigImageUrl") } } val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager diff --git a/app/src/main/kotlin/com/github/gotify/sharing/ShareActivity.kt b/app/src/main/kotlin/com/github/gotify/sharing/ShareActivity.kt index 167509e9..6cd769de 100644 --- a/app/src/main/kotlin/com/github/gotify/sharing/ShareActivity.kt +++ b/app/src/main/kotlin/com/github/gotify/sharing/ShareActivity.kt @@ -18,10 +18,10 @@ import com.github.gotify.client.api.MessageApi import com.github.gotify.client.model.Application import com.github.gotify.client.model.Message import com.github.gotify.databinding.ActivityShareBinding -import com.github.gotify.log.Log import com.github.gotify.messages.provider.ApplicationHolder import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import org.tinylog.kotlin.Logger internal class ShareActivity : AppCompatActivity() { private lateinit var binding: ActivityShareBinding @@ -33,7 +33,7 @@ internal class ShareActivity : AppCompatActivity() { binding = ActivityShareBinding.inflate(layoutInflater) setContentView(binding.root) - Log.i("Entering ${javaClass.simpleName}") + Logger.info("Entering ${javaClass.simpleName}") setSupportActionBar(binding.appBarDrawer.toolbar) val actionBar = supportActionBar if (actionBar != null) { @@ -146,7 +146,7 @@ internal class ShareActivity : AppCompatActivity() { Api.execute(messageApi.createMessage(message)) true } catch (apiException: ApiException) { - Log.e("Failed sending message", apiException) + Logger.error(apiException, "Failed sending message") false } } diff --git a/app/src/main/resources/tinylog.properties b/app/src/main/resources/tinylog.properties new file mode 100644 index 00000000..51eddf78 --- /dev/null +++ b/app/src/main/resources/tinylog.properties @@ -0,0 +1,11 @@ +writer1 = logcat +writer1.level = trace +writer1.format = {message} + +writer2 = rolling file +writer2.level = info +writer2.file = #{tinylog.directory}/log_{count}.txt +writer2.backups = 2 +writer2.format = {date: yyyy-MM-dd HH:mm:ss.SSS} {level}: {message} +writer2.policies = size: 1MB +writer2.charset = UTF-8