Android Studio中的新Relic - newrelic.properties - variants

时间:2015-05-11 14:20:31

标签: android android-studio gradle newrelic

我正在将New Relic集成到我的项目中(使用Android Studio& Gradle),该项目有2个版本。每个变体都有自己生成的令牌,我将其存储在每个变体的string.xml文件中。

New Relic documentation中,它说明了以下内容:

在项目的根目录(projectname / app)中,添加一个newrelic.properties文件,其中包含以下行:

com.newrelic.application_token=generated_token

问题是,如果我这样做,如何为正确的变体显示正确的标记?如果此文件必须出现在项目根目录中,则我无法为每个变体创建一个,因此我不得不对两个变体使用相同的标记,这对我的要求不起作用。< / p>

任何见解都将受到赞赏。

2 个答案:

答案 0 :(得分:1)

好的,所以在联系New Relic的支持团队之后,截至今天显然没有直接的解决方案,尽管他们说他们已经打开了一个功能请求,所以这个问题很快就会解决。

根据我的理解,需要此文件的原因是,当使用ProGuard进行模糊处理的生产版本发生异常时,New Relic系统可以显示未混淆的错误日志。

New Relic系统在此文件的帮助下,将ProGuard mapping.txt文件上传到New Relic服务器,并根据指定的令牌将其与您的应用程序相关联。通过这种方式,New Relic可以对堆栈跟踪进行取消混淆,并使用实际类和&amp ;;显示描述性堆栈跟踪。方法名称,而不是a,b,c等。

作为一种解决方法,我被告知如果我手动上传映射文件,我可以放弃这个文件。

可以在以下位置找到映射文件:

build/outputs/proguard/release/mapping.txt  

要手动上传文件,请通过命令行执行以下操作:

curl -v -F proguard=@"<path_to_mapping.txt>" -H "X-APP-LICENSE-KEY:<APPLICATION_TOKEN>" https://mobile-symbol-upload.newrelic.com/symbol

必须对每个使用ProGuard进行混淆的变体(通常是发布版本)进行此操作。

Source

希望这有助于其他人。

答案 1 :(得分:1)

我解决了创建一些Gradle任务的问题。请看一下https://discuss.newrelic.com/t/how-to-set-up-newrelic-properties-file-for-project-with-multiple-build-variants/46176/5

我遵循的代码对我来说非常有效。

  1. 在字符串资源文件上添加New Relic应用程序令牌。即:api.xml。

  2. 创建一个新的Gradle文件。即:newrelic-util.gradle。

  3. 在新创建的Gradle文件上添加以下内容:

    apply plugin: 'com.android.application'
    
    android.applicationVariants.all { variant ->
    
    //<editor-fold desc="Setup New Relic property file">
    
    def variantName = variant.name.capitalize()
    def newRelicTasksGroup = "newrelic"
    def projectDirPath = project.getProjectDir().absolutePath
    def newRelicPropertyFileName = "newrelic.properties"
    def newRelicPropertyFilePath = "${projectDirPath}/${newRelicPropertyFileName}"
    
    // Cleanup task for New Relic property file creation process.
    def deleteNewRelicPropertyFile = "deleteNewRelicPropertyFile"
    def taskDeleteNewRelicPropertyFile = project.tasks.findByName(deleteNewRelicPropertyFile)
    
    if (!taskDeleteNewRelicPropertyFile) {
        taskDeleteNewRelicPropertyFile = tasks.create(name: deleteNewRelicPropertyFile) {
            group = newRelicTasksGroup
            description = "Delete the newrelic.properties file on project dir."
    
            doLast {
                new File("${newRelicPropertyFilePath}").with {
                    if (exists()) {
                        logger.lifecycle("Deleting file ${absolutePath}.")
                        delete()
                    } else {
                        logger.lifecycle("Nothing to do. File ${absolutePath} not found.")
                    }
                }
            }
        }
    }
    
    /*
     * Fix for warning message reported by task "newRelicMapUploadVariantName"
     * Message:
     * [newrelic] newrelic.properties was not found! Mapping file for variant [variantName] not uploaded.
     * New Relic discussion:
     * https://discuss.newrelic.com/t/how-to-set-up-newrelic-properties-file-for-project-with-multiple-build-variants/46176
     */
    
    def requiredTaskName = "assemble${variantName}"
    def taskAssembleByVariant = project.tasks.findByName(requiredTaskName)
    def createNewRelicPropertyFileVariantName = "createNewRelicPropertyFile${variantName}"
    
    // 0. Searching task candidate to be dependent.
    if (taskAssembleByVariant) {
        logger.debug("Candidate task to be dependent found: ${taskAssembleByVariant.name}")
    
        // 1. Task creation
        def taskCreateNewRelicPropertyFile = tasks.create(name: createNewRelicPropertyFileVariantName) {
            group = newRelicTasksGroup
            description = "Generate the newrelic.properties file on project dir.\nA key/value propety " +
                    "will be written in file to be consumed by newRelicMapUploadVariantName task."
    
            logger.debug("Creating task: ${name}")
    
            doLast {
                def newRelicPropertyKey = "com.newrelic.application_token"
                def newRelicStringResourceKey = "new_relic_key"
                def targetResourceFileName = "api.xml"
                def variantXmlResourceFilePath = "${projectDirPath}/src/${variant.name}/res/values/${targetResourceFileName}"
                def mainXmlResourceFilePath = "${projectDirPath}/src/main/res/values/${targetResourceFileName}"
                def xmlResourceFilesPaths = [variantXmlResourceFilePath, mainXmlResourceFilePath]
    
                xmlResourceFilesPaths.any { xmlResourceFilePath ->
                    // 1.1. Searching xml resource file.
                    def xmlResourceFile = new File(xmlResourceFilePath)
                    if (xmlResourceFile.exists()) {
                        logger.lifecycle("Reading property from xml resource file: ${xmlResourceFilePath}.")
    
                        // 1.2. Searching for string name new_relic_key api.xml resource file.
                        def nodeResources = new XmlParser().parse(xmlResourceFile)
                        def nodeString = nodeResources.find {
                            Node nodeString -> nodeString.'@name'.toString() == newRelicStringResourceKey
                        }
    
                        // 1.3. Checking if string name new_relic_key was found.
                        if (nodeString != null) {
                            def newRelicApplicationToken = "${nodeString.value()[0]}"
                            logger.lifecycle("name:${nodeString.'@name'.toString()};" +
                                    "value:${newRelicApplicationToken}")
    
                            // 1.4 Checking the content of newRelicApplicationToken
                            if (newRelicApplicationToken == 'null' || newRelicApplicationToken.allWhitespace) {
                                logger.warn("Invalid value for key ${newRelicStringResourceKey}. " +
                                        "Please, consider configuring a value for key ${newRelicStringResourceKey}" +
                                        " on ${xmlResourceFile.name} resource file for buildVariant: ${variantName}. " +
                                        "The ${newRelicPropertyFileName} will be not created.")
                                return true // break the loop
                            }
    
                            // 1.5. File creation.
                            File fileProperties = new File(newRelicPropertyFilePath)
                            fileProperties.createNewFile()
                            logger.lifecycle("File ${fileProperties.absolutePath} created.")
    
                            // 1.6. Writing content on properties file.
                            def fileComments = "File generated dynamically by gradle task ${createNewRelicPropertyFileVariantName}.\n" +
                                    "Don't change it manually.\n" +
                                    "Don't track it on VCS."
                            new Properties().with {
                                load(fileProperties.newDataInputStream())
                                setProperty(newRelicPropertyKey, newRelicApplicationToken.toString())
                                store(fileProperties.newWriter(), fileComments)
                            }
    
                            logger.lifecycle("Properties saved on file ${fileProperties.absolutePath}.")
                            return true // break the loop
                        } else {
                            logger.warn("The key ${newRelicStringResourceKey} was not found on ${xmlResourceFile.absolutePath}.\n" +
                                    "Please, consider configuring a key/value on ${xmlResourceFile.name} resource file for buildVariant: ${variantName}.")
                            return // continue to next xmlResourceFilePath
                        }
                    } else {
                        logger.error("Resource file not found: ${xmlResourceFile.absolutePath}")
                        return // continue next xmlResourceFilePath
                    }
                }
            }
        }
    
        // 2. Task dependency setup
        // To check the task dependencies, use:
        // logger.lifecycle("Task ${name} now depends on tasks:")
        // dependsOn.forEach { dep -> logger.lifecycle("\tTask: ${dep}") }
        tasks['clean'].dependsOn taskDeleteNewRelicPropertyFile
        taskCreateNewRelicPropertyFile.dependsOn taskDeleteNewRelicPropertyFile
        taskAssembleByVariant.dependsOn taskCreateNewRelicPropertyFile
    } else {
        logger.error("Required task ${requiredTaskName} was not found. " +
                "The task ${createNewRelicPropertyFileVariantName} will be not created.")
    }
    
    //</editor-fold>
    

    }

  4. 在app / build.gradle文件上,应用Gradle文件。

    从以下位置应用:“ ./ newrelic-util.gradle”

就是这样。我在项目应用程序目录上创建了一个名为newrelic-util.gradle的文件。如果执行任务assembleAnyVariantName,将首先执行任务createNewRelicPropertyFileAnyVarianteName。提示:不要跟踪生成的文件newrelic.properties文件。在您的VCS上忽略它。

此外,任务deleteNewRelicPropertyFile将直接在任务“ clean”和“ createNewRelicPropertyFileAnyVarianteName”之前执行,以避免文件使用错误的New Relic应用程序令牌。