如何过滤Azure日志,或WCF数据服务的筛选器(入门版)

41

我在查看我的Azure日志WADLogsTable并希望筛选结果,但是我不知道如何操作。页面上有一个文本框:

“输入WCF数据服务过滤器以限制返回的实体”

什么是“WCF数据服务过滤器”的语法?以下语法会导致无效值类型错误,提示“指定的值无效。”:

Timestamp gt '2011-04-20T00:00'

我离答案近吗?有没有方便的语法参考资料?

3个回答

72

这个查询应该按照以下格式:

Timestamp gt datetime'2011-04-20T00:00:00'

记得把那个datetime放进去是重要的部分。

这总是让我困扰,所以我使用OData概述作为参考。


1
谢谢!这个可行,但是我需要先稍作调整。我必须添加秒部分。可能是 Azure 的一个小问题。 - gilly3
只要添加秒数,它就能正常工作。knightpfhor,你能编辑一下回复吗? - Miguel Madero
2
+1,同时 Timestamp 必须以完全相同的方式大写,否则结果始终为空。 - sharptooth
这段代码没有特定的目的,但是它使用的逻辑运算符是 and 而不是 &,我曾经花费了大量时间来寻找这个问题。 - Casey
@knightpfhor,感谢您包含 OData 标准的链接。 - Manfred

12

除了knightffhor的回答之外,您肯定可以编写一个按时间戳过滤的查询,但是这不是推荐的方法,因为在“时间戳”属性上进行查询将导致全表扫描。相反,应该使用PartitionKey属性查询此表。我会在这里复制我的另一个帖子的回答(Can I capture Performance Counters for an Azure Web/Worker Role remotely...?):

"这里的关键是要了解如何有效地查询此表(以及其他诊断表)。我们从诊断表中想要的一件事情就是获取某个时间段内的数据。我们的自然本能会是在时间戳属性上查询此表。但是这是一个糟糕的设计选择,因为在Azure表中,数据是根据PartitionKey和RowKey索引的。查询任何其他属性将导致全表扫描,当表包含大量数据时,这将创建问题。这些日志表的好处在于,PartitionKey值在某种程度上表示收集数据点时的日期/时间。基本上,PartitionKey是通过使用DateTime.Ticks(在UTC中)的高位比特创建的。因此,如果您要获取某个日期/时间范围的数据,则首先需要计算您的范围(在UTC中)的Ticks,然后在其前面添加“0”并在查询中使用这些值。 如果您正在使用REST API进行查询,则应使用以下语法: PartitionKey ge '0<从UTC中的日期/时间ticks>' and PartitionKey le '0<到UTC的日期/时间>'。"

我写了一篇关于如何针对表存储编写WCF查询的博客文章,您可能会发现有用:http://blog.cerebrata.com/specifying-filter-criteria-when-querying-azure-table-storage-using-rest-api/

如果您正在寻找一个第三方工具来查看和管理诊断数据,我建议您看一下我们的产品 Azure Diagnostics Manager:/Products/AzureDiagnosticsManager。这个工具是专门用于展示和管理 Windows Azure 诊断数据的。


1
你还可以查看这个讨论:http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/1c030d5d-d871-4fbd-88be-bc4755b33fcc/. 总的来说,如果没有对时间戳进行索引(分区键/行键),就不要使用时间戳进行查询。 - David Faivre
Cerebrata博客的链接已经失效了,这篇文章还能在其他地方找到吗? - Opsimath
已更新答案,正确链接为:http://blog.cerebrata.com/specifying-filter-criteria-when-querying-azure-table-storage-using-rest-api/。 - Gaurav Mantri

4

我接受的答案在通过Visual Studio直接查询表格方面对我非常有帮助。然而,最终我需要一个更强大的解决方案。我使用这里获得的技巧开发了一些C#类,让我可以使用LINQ来查询表格。如果对查看此问题的其他人有用,以下是我现在查询Azure日志的大致方法。

创建一个继承自Microsoft.WindowsAzure.StorageClient.TableServiceEntity的类,以表示“WADLogsTable”表中的所有数据:

public class AzureDiagnosticEntry : TableServiceEntity
{
    public long EventTickCount { get; set; }
    public string DeploymentId { get; set; }
    public string Role { get; set; }
    public string RoleInstance { get; set; }
    public int EventId { get; set; }
    public int Level { get; set; }
    public int Pid { get; set; }
    public int Tid { get; set; }
    public string Message { get; set; }
    public DateTime EventDateTime
    {
        get
        {
            return new DateTime(EventTickCount, DateTimeKind.Utc);
        }
    }
}

创建一个继承自Microsoft.WindowsAzure.StorageClient.TableServiceContext的类,并引用新定义的数据对象类:
public class AzureDiagnosticContext : TableServiceContext
{
    public AzureDiagnosticContext(string baseAddress, StorageCredentials credentials)
        : base(baseAddress, credentials)
    {
        this.ResolveType = s => typeof(AzureDiagnosticEntry);
    }

    public AzureDiagnosticContext(CloudStorageAccount storage)
        : this(storage.TableEndpoint.ToString(), storage.Credentials) { }

    // Helper method to get an IQueryable.  Hard code "WADLogsTable" for this class
    public IQueryable<AzureDiagnosticEntry> Logs
    {
        get
        {
            return CreateQuery<AzureDiagnosticEntry>("WADLogsTable");
        }
    }
}

我有一个帮助方法,可以从配置设置中创建一个CloudStorageAccount
public CloudStorageAccount GetStorageAccount()
{
    CloudStorageAccount.SetConfigurationSettingPublisher(
        (name, setter) => setter(RoleEnvironment.GetConfigurationSettingValue(name)));
    string configKey = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
    return CloudStorageAccount.FromConfigurationSetting(configKey);
}

我从CloudStorageAccount创建一个AzureDiagnosticContext,用它来查询我的日志:
public IEnumerable<AzureDiagnosticEntry> GetAzureLog(DateTime start, DateTime end)
{
    CloudStorageAccount storage = GetStorageAccount();
    AzureDiagnosticContext context = new AzureDiagnosticContext(storage);
    string startTicks = "0" + start.Ticks;
    string endTicks = "0" + end.Ticks;
    IQueryable<AzureDiagnosticEntry> query = context.Logs.Where(
        e => e.PartitionKey.CompareTo(startTicks) > 0 &&
             e.PartitionKey.CompareTo(endTicks) < 0);
    CloudTableQuery<AzureDiagnosticEntry> tableQuery = query.AsTableServiceQuery();
    IEnumerable<AzureDiagnosticEntry> results = tableQuery.Execute();
    return results;
}

这种方法利用了Gaurav's answer中的性能技巧,通过筛选PartitionKey而不是Timestamp来过滤数据。
如果您想按照更多条件进行筛选,可以对返回的IEnumerable进行筛选。但是,通过对IQueryable进行筛选,您可能会获得更好的性能。您可以在方法中添加一个筛选参数,并在IQueryable.Where()内调用它。例如:
public IEnumerable<AzureDiagnosticEntry> GetAzureLog(
    DateTime start, DateTime end, Func<AzureDiagnosticEntry, bool> filter)
{
    ...
    IQueryable<AzureDiagnosticEntry> query = context.Logs.Where(
        e => e.PartitionKey.CompareTo(startTicks) > 0 &&
             e.PartitionKey.CompareTo(endTicks) < 0 &&
             filter(e));
    ...
}

最终,我实际上将大部分这些类进一步抽象为基类,以便重用查询其他表的功能,比如存储Windows事件日志的表。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接