/src/adapters/collectd/collector_collectd_parser.erl

http://github.com/schmurfy/Collector · Erlang · 124 lines · 70 code · 35 blank · 19 comment · 0 complexity · d2a6207194a529d38bdceb3e1b214f67 MD5 · raw file

  1. -module (collector_collectd_parser).
  2. -ifdef(TEST).
  3. -compile(export_all).
  4. -else.
  5. -export([unpack/1]).
  6. -endif.
  7. -include("collector.hrl").
  8. unpack(Binary) ->
  9. unpack(Binary, []).
  10. unpack(<<>>, L) -> L;
  11. unpack(Binary, L = []) ->
  12. {Rest, Packet} = parse_packet(Binary, #data{}),
  13. % io:format("Packet:~w~n", [?rec_info(data, Packet)]),
  14. unpack(Rest, [Packet|L]);
  15. unpack(Binary, L = [H|_]) ->
  16. NewPacket = H#data{values = []},
  17. {Rest, Packet} = parse_packet(Binary, NewPacket),
  18. % io:format("Packet:~w~n", [?rec_info(data, Packet)]),
  19. unpack(Rest, [Packet|L]).
  20. %% -----------
  21. %% Parse packet
  22. %% -----------
  23. parse_packet(<<>>, Packet = #data{}) -> {<<>>, Packet};
  24. parse_packet(Binary, #data{values = []} = Packet) ->
  25. {Rest, NewPacket} = parse_part(Binary, Packet),
  26. parse_packet(Rest, NewPacket);
  27. % we have a complete packet
  28. parse_packet(Binary, #data{} = Packet) ->
  29. NewPacket = Packet#data{values = lists:reverse(Packet#data.values)},
  30. {Binary, NewPacket}.
  31. %% -----------
  32. %% Parse part
  33. %% -----------
  34. parse_part(Binary, Packet) ->
  35. {PartID, Length, Rest1} = parse_part_header(Binary),
  36. {NewPacket, Rest2} = parse_part_value(Rest1, PartID, Length, Packet),
  37. {Rest2, NewPacket}.
  38. %% Unpacks part id and length from Binary. Return value is a triplet
  39. %% of those plus the Binary remainder.
  40. parse_part_header(Binary) ->
  41. <<PartID:16, Length:16, Rem/binary>> = Binary,
  42. % Length includes the 4 header bytes; we need to get rid of them.
  43. {PartID, Length - 4, Rem}.
  44. %% Takes Length bytes from Binary and transforms them to an Erlang
  45. %% expression using the part data type. The result is a tuple of
  46. %% the updated data record and the Binary remainder.
  47. parse_part_value(Binary, PartID, Length, Packet) ->
  48. <<Value:Length/binary-unit:8, Rest/binary>> = Binary,
  49. NewPacket = parse_part_value(PartID, Value, Packet),
  50. {NewPacket, Rest}.
  51. parse_part_value( 0, Value, Packet) -> Packet#data{host = parse_part_value(string, Value)};
  52. parse_part_value( 1, Value, Packet) -> Packet#data{time = parse_part_value(numeric, Value)};
  53. parse_part_value( 2, Value, Packet) -> Packet#data{plugin = parse_part_value(string, Value)};
  54. parse_part_value( 3, Value, Packet) -> Packet#data{plugin_instance = parse_part_value(string, Value)};
  55. parse_part_value( 4, Value, Packet) -> Packet#data{type = parse_part_value(string, Value)};
  56. parse_part_value( 5, Value, Packet) -> Packet#data{type_instance = parse_part_value(string, Value)};
  57. parse_part_value( 6, Value, Packet) -> Packet#data{values = parse_part_value(values, Value)};
  58. parse_part_value( 7, Value, Packet) -> Packet#data{interval = parse_part_value(numeric, Value)};
  59. parse_part_value(100, Value, Packet) -> Packet#data{message = parse_part_value(string, Value)};
  60. parse_part_value(101, Value, Packet) -> Packet#data{severity = parse_part_value(numeric, Value)}.
  61. parse_part_value(string, Value) ->
  62. % Remove null byte.
  63. Length = size(Value) - 1,
  64. <<String:Length/binary-unit:8, _:8>> = Value,
  65. % binary_to_list(String);
  66. String;
  67. parse_part_value(numeric, <<Value:64>>) ->
  68. Value;
  69. parse_part_value(values, Value) ->
  70. <<Count:16, Rest/binary>> = Value,
  71. % Split the binary into types and values.
  72. {Types, Values} = split_binary(Rest, Count),
  73. parse_values(Count, Types, Values, []).
  74. parse_values(0, <<>>, <<>>, Result) -> Result;
  75. parse_values(Count, Types, Values, Result) ->
  76. % Extract the first type id and the first value.
  77. <<TypeID:8, RemTypes/binary>> = Types,
  78. <<Value:64/binary-unit:1, RemValues/binary>> = Values,
  79. parse_values(Count - 1, RemTypes, RemValues, [unpack_value(TypeID, Value)|Result]).
  80. unpack_value(0, <<Value:64>>) -> {counter, Value};
  81. unpack_value(1, <<Value:8/bytes>>) -> {gauge, ntohd(Value)};
  82. unpack_value(2, <<Value:64>>) -> {derive, Value};
  83. unpack_value(3, <<Value:64>>) -> {absolute, Value}.
  84. ntohd(Value) ->
  85. binary_to_term(
  86. list_to_binary(
  87. [131, 70, lists:reverse(binary_to_list(Value))] ),
  88. [safe]
  89. ).