查看和配置通过 NLog 基础架构生成的 Orchestrator 诊断日志
Orchestrator 诊断日志
这些是 UiPath™ Orchestrator 生成的有关其行为的诊断日志。
启用 UiPath Orchestrator 诊断日志
成功安装 UiPath Orchestrator 后,将启用 UiPath Orchestrator 诊断日志。它们依赖于 NLog 基础架构,其配置可以在 UiPath.Orchestrator.dll.config 文件中的 <nlog> 标签下找到。
请注意,无论用户选择哪种语言,Orchestrator 的服务器异常以及“作业详细信息”窗口上的堆栈跟踪都以英语记录。
UiPath Orchestrator 诊断日志的目标
所有应用程序日志都以最低日志记录级别 Information 记录到事件查看器。这由 UiPath.Orchestrator.dll.config 文件中的以下行指定:
<target xsi:type="EventLog" name="eventLog" layout="${message}" source="Orchestrator" log="Application" />
<logger name="*" minlevel="Info" writeTo="eventLog" />
作业计划程序生成的日志具有单独的目标和记录器:
<target xsi:type="EventLog" name="eventLogQuartz" layout="[Quartz] ${message} ${onexception: ${exception:format=tostring}}" source="Orchestrator" log="Application" />
<logger name="Orchestrator.Quartz.*" minlevel="Info" writeTo="eventLogQuartz" />
示例:
Could not create Quartz Job
业务规则和其他验证规则生成的日志具有单独的目标和记录器:
<target xsi:type="EventLog" name="businessExceptionEventLog" layout="${message}${onexception:${exception:format=tostring:maxInnerExceptionLevel=5:innerFormat=tostring}}" source="Orchestrator.BusinessException" log="Application" />
<logger name="BusinessException.*" minlevel="Info" writeTo="businessExceptionEventLog" final="true" />
在以下情况下,这些类型的错误消息会记录在事件查看器中:
- 验证问题,例如:
Invalid username/email address or password.The machine name DOC is already taken
- 业务冲突,例如:
License expired!The floating robot's session is already active on machine ROQADOCS06!The robots already have pending jobs for this Process.
- 未找到异常,例如:
QueueName1 does not exist.
Orchestrator 执行日志
Orchestrator 执行日志由与其连接的机器人发送,并显示在“作业”或“机器人”页面的“日志”部分中。应用程序从机器人接收数据,添加自己的参数( TenantID 、 FolderID ),并将消息转发到不同的目标,如UiPath.Orchestrator.dll.config文件的<nlog>部分中所指定。
Orchestrator 执行日志的目标
默认情况下,所有机器人日志都发送到默认 Orchestrator 数据库的“日志”表,UiPath Orchestrator 还将其他信息存储在该数据库中。
但是,您可以通过在 UiPath.Orchestrator.dll.config 文件的 target xsi:type="Database" connectionString="..." 部分中进行配置,选择将机器人日志发送到其他数据库。
“日志”页面显示默认数据库的“日志”表中的信息。因此,如果此部分不存在,或者日志保存到其他数据库中,则页面为空。所有参数都应符合表格架构,如下所示:
<target xsi:type="Database" name="database" connectionString="${ui-connection-strings:item=Default}" keepConnection="true">
<commandText>
insert into dbo.Logs (OrganizationUnitId, TenantId, TimeStamp, Level, WindowsIdentity, ProcessName, JobKey, Message, RawMessage)
values (@organizationUnitId, @tenantId, @timeStamp, @level, @windowsIdentity, @processName, @jobId, @message, @rawMessage)
</commandText>
<parameter name="@organizationUnitId" layout="${event-properties:item=organizationUnitId}" />
<parameter name="@tenantId" layout="${event-properties:item=tenantId}" />
<parameter name="@timeStamp" layout="${date}" />
<parameter name="@level" layout="${event-properties:item=levelOrdinal}" />
<parameter name="@windowsIdentity" layout="${event-properties:item=windowsIdentity}" />
<parameter name="@processName" layout="${event-properties:item=processName}" />
<parameter name="@jobId" layout="${event-properties:item=jobId}" />
<parameter name="@message" layout="${message}" />
<parameter name="@rawMessage" layout="${event-properties:item=rawMessage}" />
</target>
<logger name="Robot.*" writeTo="database" final="true" />
<target xsi:type="Database" name="database" connectionString="${ui-connection-strings:item=Default}" keepConnection="true">
<commandText>
insert into dbo.Logs (OrganizationUnitId, TenantId, TimeStamp, Level, WindowsIdentity, ProcessName, JobKey, Message, RawMessage)
values (@organizationUnitId, @tenantId, @timeStamp, @level, @windowsIdentity, @processName, @jobId, @message, @rawMessage)
</commandText>
<parameter name="@organizationUnitId" layout="${event-properties:item=organizationUnitId}" />
<parameter name="@tenantId" layout="${event-properties:item=tenantId}" />
<parameter name="@timeStamp" layout="${date}" />
<parameter name="@level" layout="${event-properties:item=levelOrdinal}" />
<parameter name="@windowsIdentity" layout="${event-properties:item=windowsIdentity}" />
<parameter name="@processName" layout="${event-properties:item=processName}" />
<parameter name="@jobId" layout="${event-properties:item=jobId}" />
<parameter name="@message" layout="${message}" />
<parameter name="@rawMessage" layout="${event-properties:item=rawMessage}" />
</target>
<logger name="Robot.*" writeTo="database" final="true" />
其他目标可以通过配置UiPath.Orchestrator.dll.config文件添加到日志中。可在此处找到可用目标列表。
升级 Orchestrator 时,系统会删除并重新创建 Nlog 目标,如下所示:
- 升级到 2022.4 后, Nlog 数据库目标将恢复为其默认值。
- 升级到 2022.10 后,Nlog 数据库目标将被删除,并替换为经过改进的新目标。其中包括
database、monitoring和insightsRobotLogs目标。
如果表中存储的机器人日志数量超过 100 万条,我们建议创建以下索引以提高搜索性能:
CREATE NONCLUSTERED INDEX [IX_Search] ON [dbo].[Logs]
(
[TenantId] ASC,
[OrganizationUnitId] ASC,
[Level] ASC,
[TimeStamp] DESC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_Search] ON [dbo].[Logs]
(
[TenantId] ASC,
[OrganizationUnitId] ASC,
[Level] ASC,
[TimeStamp] DESC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
Elasticsearch 服务器
默认情况下,从安装脚本中配置 Elasticsearch 目标。每个租户的索引都不同,但这可以通过 <nlog> 节中指定的目标进行配置。
对于低于 Elasticsearch 8.0 的版本:
<target name="robotElasticBuffer" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" name="robotElastic" uri="uritoelasticsearchnode" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="logEvent" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,organizationId,indexName" />
</target>
</target>
<target name="robotElasticBuffer" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" name="robotElastic" uri="uritoelasticsearchnode" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="logEvent" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,organizationId,indexName" />
</target>
</target>
对于 Elasticsearch 8.0 及更高版本:
<target name="robotElasticBuffer" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" name="robotElastic" uri="uritoelasticsearchnode" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="" enableApiVersioningHeader="true" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,organizationId,indexName" />
</target>
</target>
<target name="robotElasticBuffer" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" name="robotElastic" uri="uritoelasticsearchnode" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="" enableApiVersioningHeader="true" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,organizationId,indexName" />
</target>
</target>
为了使 Elasticsearch 8.0 及更高版本正常工作,请按如下方式设置这些参数:
documentType为空。- 将
enableApiVersioningHeader设置为true。备注:将机器人日志保存到 Elasticsearch 服务器的选项仅在配置后生效,并且不会追溯性应用。这意味着您将无法再访问在配置选项时数据库中已有的任何日志,因为只能从单个目标检索和显示日志。
X-PACK 身份验证
默认情况下,如果您拥有基本许可证或试用许可证,则 Elasticsearch 安全功能处于禁用状态。 我们强烈建议您启用它们。
用户名和密码身份验证
要启用通过用户名和密码进行的身份验证,您需要执行以下步骤:
- 配置 Elasticsearch 服务器,如下所示:
- 将
xpack.security.enabled设置添加到elasticsearch.yml配置文件。 - 设置用户名和密码。
- 将
有关更多详细信息,请参阅 Elasticsearch 文档。
- 配置 Orchestrator 的
UiPath.Orchestrator.dll.config文件,如下所示:
- 选项 1 :如果不使用 NLog 目标,则需要配置以下参数:
Logs.Elasticsearch.Username和Logs.Elasticsearch.Password。 确保其值与步骤 1 中的 Elasticsearch 设置匹配。 - 选项 2 :如果将
Logs.RobotLogs.ReadTarget设置为 NLog 目标(例如robotElasticBuffer),并且未指定Logs.Elasticsearch.Nodes设置,请通过添加以下内容来配置目标:requireAuth="true" username="XPACKuser" password="p@$$w0rd"。 确保这些参数值与步骤 1 中的 Elasticsearch 设置匹配。
有关这些参数的更多信息,请参阅UiPath.Orchestrator.dll.config页面。有关配置示例,请参阅以下内容:
<target name="robotElasticBuffer" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" name="robotElastic" uri="" requireAuth="true" username="XPACKusername" password="p@$$w0rd" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="logEvent" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,indexName" />
</target>
<target name="robotElasticBuffer" xsi:type="BufferingWrapper" flushTimeout="5000">
<target xsi:type="ElasticSearch" name="robotElastic" uri="" requireAuth="true" username="XPACKusername" password="p@$$w0rd" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="logEvent" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,indexName" />
</target>
- 选项 3 :如果
Logs.RobotLogs.ReadTarget设置为 NLog 目标(例如robotElasticBuffer),并且通过Logs.Elasticsearch.Nodes设置指定了 Elasticsearch 节点,则需要显式配置它(因为它会覆盖 NLog 目标设置) ,并确保同时添加以下内容:requireAuth="true" username="XPACKuser" password="p@$$w0rd"。 确保这些参数值与步骤 1 中的 Elasticsearch 设置匹配。
OAuth 2 身份验证
要切换到 OAuth2 作为 Elasticsearch 的身份验证方法,您需要执行以下步骤。 请注意,您需要提供当前凭据才能切换到此基于令牌的身份验证方法。
-
配置 Elasticsearch 服务器,如下所示:
- 为传输层启用 TLS (HTTPS)。
- 更新
elasticsearch.yml配置文件中的以下设置:
xpack.security.authc.token.enabled: truexpack.security.enabled: truexpack.security.authc.token.timeout- 此设置为可选设置,用于控制令牌的有效期。 默认情况下,其值设置为 20 分钟。
有关更多详细信息,请参阅 Elasticsearch 文档。
- 更新 Orchestrator 的
UiPath.Orchestrator.dll.config文件中的以下参数,以反映您在步骤 1 中选择的设置。Logs.Elasticsearch.TlsEnabled = ”true”- 默认情况下,此参数设置为true,并确保启用 TLC (HTTPS)。Logs.Elasticsearch.OAuthEnabled = ”true”- 默认情况下,此参数设置为false。有关更多信息,请参阅Logs.Elasticsearch.OAuthEnabled。Logs.Elasticsearch.OAuthExpireInSeconds = ”1200”- 除非在 Elasticsearchxpack.security.authc.token.timeout设置中更改了1200的默认值,否则此参数为可选。此参数的值必须与 Elasticsearch 配置中的值相同。有关更多信息,请参见Logs.Elasticsearch.OAuthExpireInSeconds。备注:前两个步骤可帮助您配置基于令牌的身份验证机制以读取日志。 如果您使用 NLog,则需要执行其他步骤。
- 要为 Nlog 启用 OAuth2,还要务必在 Orchestrator 的
UiPath.Orchestrator.dll.config文件中配置以下参数。请注意,您必须在 Elasticsearch 中填写用户名和密码以进行身份验证,因为初始令牌是根据这些凭据生成的。OAuthEnabled = “true”- 默认情况下,它设置为false。有关更多信息,请参阅UiPath.Orchestrator.dll.config页面。重要提示:如果
Logs.RobotLogs.ReadTarget设置为 NLog 目标(例如robotElasticBuffer),并且未指定Logs.Elasticsearch.Nodes设置,则从 NLog 目标配置中填充Logs.Elasticsearch.OAuthEnabled。 相同的逻辑适用于用户名和密码。
API 密钥身份验证
要通过 API 密钥启用身份验证,请按照下面列出的步骤操作。
- 请按照这些步骤生成 API 密钥。
- 将 API 密钥作为密码存储在 Azure 密钥保险库中。
- 使用您的数据配置以下 Nlog 目标参数,从而在 Orchestrator 和允许检索密钥的密钥保险库之间创建连接:
apiKeyEnabled="true" apiKeyProvider="AzureKeyVault" apiKeySecretName="<SecretName>" azureKeyVaultUri="<KeyVaultUri>" azureKeyVaultDirectoryId="<KeyVaultDirectoryId>" azureKeyVaultClientId="<KeyVaultClientId>" azureKeyVaultCertificateThumbprint="<KeyVaultCertificateThumbprint>" azureKeyVaultCertificateStoreLocation="CurrentUser/LocalMachine"apiKeyEnabled="true" apiKeyProvider="AzureKeyVault" apiKeySecretName="<SecretName>" azureKeyVaultUri="<KeyVaultUri>" azureKeyVaultDirectoryId="<KeyVaultDirectoryId>" azureKeyVaultClientId="<KeyVaultClientId>" azureKeyVaultCertificateThumbprint="<KeyVaultCertificateThumbprint>" azureKeyVaultCertificateStoreLocation="CurrentUser/LocalMachine"
以下参数需要使用您的值进行编辑:
<SecretName>- 您在密钥保险库中为 API 密钥设置的名称<KeyVaultUri>- 密钥保险库的 URI<KeyVaultDirectoryId>- 您的密钥保险库目录 ID<KeyVaultClientId>- 您的密钥保险库客户端 ID<KeyVaultCertificateThumbprint>- 密钥保险库证书的指纹CurrentUser/LocalMachine- 证书的存储位置
API 密钥过期时间
默认情况下,API 密钥不会过期,但您仍然可以选择为其设置过期日期。
如果您的 API 密钥设置为过期,则必须在过期日期之前生成一个新密钥并将其存储在密钥保险库中,以确保 Orchestrator 始终可以检索有效密钥。
Orchestrator 每 15 分钟从密钥保险库读取 API 密钥,因此这是传播新密钥之前可以预期的最大延迟量。